Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs:
  fs/9p: Add hardlink support to .u extension
  9P2010.L handshake: .L protocol negotiation
  9P2010.L handshake: Remove "dotu" variable
  9P2010.L handshake: Add mount option
  9P2010.L handshake: Add VFS flags
  net/9p: Handle mount errors correctly.
  net/9p: Remove MAX_9P_CHAN limit
  net/9p: Add multi channel support.
This commit is contained in:
Linus Torvalds 2010-03-05 13:25:24 -08:00
commit b13d3c6e8a
12 changed files with 238 additions and 144 deletions

View File

@ -151,7 +151,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
if (access == V9FS_ACCESS_SINGLE) if (access == V9FS_ACCESS_SINGLE)
return ERR_PTR(-EPERM); return ERR_PTR(-EPERM);
if (v9fs_extended(v9ses)) if (v9fs_proto_dotu(v9ses))
uname = NULL; uname = NULL;
else else
uname = v9ses->uname; uname = v9ses->uname;

View File

@ -241,7 +241,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
list_add(&v9ses->slist, &v9fs_sessionlist); list_add(&v9ses->slist, &v9fs_sessionlist);
spin_unlock(&v9fs_sessionlist_lock); spin_unlock(&v9fs_sessionlist_lock);
v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER; v9ses->flags = V9FS_PROTO_2000U | V9FS_ACCESS_USER;
strcpy(v9ses->uname, V9FS_DEFUSER); strcpy(v9ses->uname, V9FS_DEFUSER);
strcpy(v9ses->aname, V9FS_DEFANAME); strcpy(v9ses->aname, V9FS_DEFANAME);
v9ses->uid = ~0; v9ses->uid = ~0;
@ -262,13 +262,13 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
goto error; goto error;
} }
if (!v9ses->clnt->dotu) if (!p9_is_proto_dotu(v9ses->clnt))
v9ses->flags &= ~V9FS_EXTENDED; v9ses->flags &= ~V9FS_PROTO_2000U;
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
/* for legacy mode, fall back to V9FS_ACCESS_ANY */ /* for legacy mode, fall back to V9FS_ACCESS_ANY */
if (!v9fs_extended(v9ses) && if (!v9fs_proto_dotu(v9ses) &&
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) { ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
v9ses->flags &= ~V9FS_ACCESS_MASK; v9ses->flags &= ~V9FS_ACCESS_MASK;

View File

@ -23,7 +23,8 @@
/** /**
* enum p9_session_flags - option flags for each 9P session * enum p9_session_flags - option flags for each 9P session
* @V9FS_EXTENDED: whether or not to use 9P2000.u extensions * @V9FS_PROTO_2000U: whether or not to use 9P2000.u extensions
* @V9FS_PROTO_2010L: whether or not to use 9P2010.l extensions
* @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy * @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy
* @V9FS_ACCESS_USER: a new attach will be issued for every user (default) * @V9FS_ACCESS_USER: a new attach will be issued for every user (default)
* @V9FS_ACCESS_ANY: use a single attach for all users * @V9FS_ACCESS_ANY: use a single attach for all users
@ -32,11 +33,12 @@
* Session flags reflect options selected by users at mount time * Session flags reflect options selected by users at mount time
*/ */
enum p9_session_flags { enum p9_session_flags {
V9FS_EXTENDED = 0x01, V9FS_PROTO_2000U = 0x01,
V9FS_ACCESS_SINGLE = 0x02, V9FS_PROTO_2010L = 0x02,
V9FS_ACCESS_USER = 0x04, V9FS_ACCESS_SINGLE = 0x04,
V9FS_ACCESS_ANY = 0x06, V9FS_ACCESS_USER = 0x08,
V9FS_ACCESS_MASK = 0x06, V9FS_ACCESS_ANY = 0x0C,
V9FS_ACCESS_MASK = 0x0C,
}; };
/* possible values of ->cache */ /* possible values of ->cache */
@ -121,7 +123,12 @@ static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
return (inode->i_sb->s_fs_info); return (inode->i_sb->s_fs_info);
} }
static inline int v9fs_extended(struct v9fs_session_info *v9ses) static inline int v9fs_proto_dotu(struct v9fs_session_info *v9ses)
{ {
return v9ses->flags & V9FS_EXTENDED; return v9ses->flags & V9FS_PROTO_2000U;
}
static inline int v9fs_proto_dotl(struct v9fs_session_info *v9ses)
{
return v9ses->flags & V9FS_PROTO_2010L;
} }

View File

@ -135,7 +135,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
while (rdir->head < rdir->tail) { while (rdir->head < rdir->tail) {
err = p9stat_read(rdir->buf + rdir->head, err = p9stat_read(rdir->buf + rdir->head,
buflen - rdir->head, &st, buflen - rdir->head, &st,
fid->clnt->dotu); fid->clnt->proto_version);
if (err) { if (err) {
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
err = -EIO; err = -EIO;

View File

@ -61,7 +61,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file); P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
v9ses = v9fs_inode2v9ses(inode); v9ses = v9fs_inode2v9ses(inode);
omode = v9fs_uflags2omode(file->f_flags, v9fs_extended(v9ses)); omode = v9fs_uflags2omode(file->f_flags, v9fs_proto_dotu(v9ses));
fid = file->private_data; fid = file->private_data;
if (!fid) { if (!fid) {
fid = v9fs_fid_clone(file->f_path.dentry); fid = v9fs_fid_clone(file->f_path.dentry);
@ -77,7 +77,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
i_size_write(inode, 0); i_size_write(inode, 0);
inode->i_blocks = 0; inode->i_blocks = 0;
} }
if ((file->f_flags & O_APPEND) && (!v9fs_extended(v9ses))) if ((file->f_flags & O_APPEND) && (!v9fs_proto_dotu(v9ses)))
generic_file_llseek(file, 0, SEEK_END); generic_file_llseek(file, 0, SEEK_END);
} }

View File

@ -60,7 +60,7 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
res = mode & 0777; res = mode & 0777;
if (S_ISDIR(mode)) if (S_ISDIR(mode))
res |= P9_DMDIR; res |= P9_DMDIR;
if (v9fs_extended(v9ses)) { if (v9fs_proto_dotu(v9ses)) {
if (S_ISLNK(mode)) if (S_ISLNK(mode))
res |= P9_DMSYMLINK; res |= P9_DMSYMLINK;
if (v9ses->nodev == 0) { if (v9ses->nodev == 0) {
@ -102,21 +102,21 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
if ((mode & P9_DMDIR) == P9_DMDIR) if ((mode & P9_DMDIR) == P9_DMDIR)
res |= S_IFDIR; res |= S_IFDIR;
else if ((mode & P9_DMSYMLINK) && (v9fs_extended(v9ses))) else if ((mode & P9_DMSYMLINK) && (v9fs_proto_dotu(v9ses)))
res |= S_IFLNK; res |= S_IFLNK;
else if ((mode & P9_DMSOCKET) && (v9fs_extended(v9ses)) else if ((mode & P9_DMSOCKET) && (v9fs_proto_dotu(v9ses))
&& (v9ses->nodev == 0)) && (v9ses->nodev == 0))
res |= S_IFSOCK; res |= S_IFSOCK;
else if ((mode & P9_DMNAMEDPIPE) && (v9fs_extended(v9ses)) else if ((mode & P9_DMNAMEDPIPE) && (v9fs_proto_dotu(v9ses))
&& (v9ses->nodev == 0)) && (v9ses->nodev == 0))
res |= S_IFIFO; res |= S_IFIFO;
else if ((mode & P9_DMDEVICE) && (v9fs_extended(v9ses)) else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
&& (v9ses->nodev == 0)) && (v9ses->nodev == 0))
res |= S_IFBLK; res |= S_IFBLK;
else else
res |= S_IFREG; res |= S_IFREG;
if (v9fs_extended(v9ses)) { if (v9fs_proto_dotu(v9ses)) {
if ((mode & P9_DMSETUID) == P9_DMSETUID) if ((mode & P9_DMSETUID) == P9_DMSETUID)
res |= S_ISUID; res |= S_ISUID;
@ -265,7 +265,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
case S_IFBLK: case S_IFBLK:
case S_IFCHR: case S_IFCHR:
case S_IFSOCK: case S_IFSOCK:
if (!v9fs_extended(v9ses)) { if (!v9fs_proto_dotu(v9ses)) {
P9_DPRINTK(P9_DEBUG_ERROR, P9_DPRINTK(P9_DEBUG_ERROR,
"special files without extended mode\n"); "special files without extended mode\n");
err = -EINVAL; err = -EINVAL;
@ -278,7 +278,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
inode->i_fop = &v9fs_file_operations; inode->i_fop = &v9fs_file_operations;
break; break;
case S_IFLNK: case S_IFLNK:
if (!v9fs_extended(v9ses)) { if (!v9fs_proto_dotu(v9ses)) {
P9_DPRINTK(P9_DEBUG_ERROR, P9_DPRINTK(P9_DEBUG_ERROR,
"extended modes used w/o 9P2000.u\n"); "extended modes used w/o 9P2000.u\n");
err = -EINVAL; err = -EINVAL;
@ -288,7 +288,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
break; break;
case S_IFDIR: case S_IFDIR:
inc_nlink(inode); inc_nlink(inode);
if (v9fs_extended(v9ses)) if (v9fs_proto_dotu(v9ses))
inode->i_op = &v9fs_dir_inode_operations_ext; inode->i_op = &v9fs_dir_inode_operations_ext;
else else
inode->i_op = &v9fs_dir_inode_operations; inode->i_op = &v9fs_dir_inode_operations;
@ -575,7 +575,8 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
flags = O_RDWR; flags = O_RDWR;
fid = v9fs_create(v9ses, dir, dentry, NULL, perm, fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
v9fs_uflags2omode(flags, v9fs_extended(v9ses))); v9fs_uflags2omode(flags,
v9fs_proto_dotu(v9ses)));
if (IS_ERR(fid)) { if (IS_ERR(fid)) {
err = PTR_ERR(fid); err = PTR_ERR(fid);
fid = NULL; fid = NULL;
@ -858,7 +859,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
if (iattr->ia_valid & ATTR_SIZE) if (iattr->ia_valid & ATTR_SIZE)
wstat.length = iattr->ia_size; wstat.length = iattr->ia_size;
if (v9fs_extended(v9ses)) { if (v9fs_proto_dotu(v9ses)) {
if (iattr->ia_valid & ATTR_UID) if (iattr->ia_valid & ATTR_UID)
wstat.n_uid = iattr->ia_uid; wstat.n_uid = iattr->ia_uid;
@ -886,6 +887,8 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
struct super_block *sb) struct super_block *sb)
{ {
char ext[32]; char ext[32];
char tag_name[14];
unsigned int i_nlink;
struct v9fs_session_info *v9ses = sb->s_fs_info; struct v9fs_session_info *v9ses = sb->s_fs_info;
inode->i_nlink = 1; inode->i_nlink = 1;
@ -897,11 +900,26 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
inode->i_uid = v9ses->dfltuid; inode->i_uid = v9ses->dfltuid;
inode->i_gid = v9ses->dfltgid; inode->i_gid = v9ses->dfltgid;
if (v9fs_extended(v9ses)) { if (v9fs_proto_dotu(v9ses)) {
inode->i_uid = stat->n_uid; inode->i_uid = stat->n_uid;
inode->i_gid = stat->n_gid; inode->i_gid = stat->n_gid;
} }
if ((S_ISREG(inode->i_mode)) || (S_ISDIR(inode->i_mode))) {
if (v9fs_proto_dotu(v9ses) && (stat->extension[0] != '\0')) {
/*
* Hadlink support got added later to
* to the .u extension. So there can be
* server out there that doesn't support
* this even with .u extension. So check
* for non NULL stat->extension
*/
strncpy(ext, stat->extension, sizeof(ext));
/* HARDLINKCOUNT %u */
sscanf(ext, "%13s %u", tag_name, &i_nlink);
if (!strncmp(tag_name, "HARDLINKCOUNT", 13))
inode->i_nlink = i_nlink;
}
}
inode->i_mode = p9mode2unixmode(v9ses, stat->mode); inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
char type = 0; char type = 0;
@ -976,7 +994,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
if (IS_ERR(fid)) if (IS_ERR(fid))
return PTR_ERR(fid); return PTR_ERR(fid);
if (!v9fs_extended(v9ses)) if (!v9fs_proto_dotu(v9ses))
return -EBADF; return -EBADF;
st = p9_client_stat(fid); st = p9_client_stat(fid);
@ -1066,7 +1084,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
struct p9_fid *fid; struct p9_fid *fid;
v9ses = v9fs_inode2v9ses(dir); v9ses = v9fs_inode2v9ses(dir);
if (!v9fs_extended(v9ses)) { if (!v9fs_proto_dotu(v9ses)) {
P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
return -EPERM; return -EPERM;
} }

View File

@ -5,7 +5,4 @@
#include <linux/virtio_ids.h> #include <linux/virtio_ids.h>
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
/* Maximum number of virtio channels per partition (1 for now) */
#define MAX_9P_CHAN 1
#endif /* _LINUX_VIRTIO_9P_H */ #endif /* _LINUX_VIRTIO_9P_H */

View File

@ -29,6 +29,19 @@
/* Number of requests per row */ /* Number of requests per row */
#define P9_ROW_MAXTAG 255 #define P9_ROW_MAXTAG 255
/** enum p9_proto_versions - 9P protocol versions
* @p9_proto_legacy: 9P Legacy mode, pre-9P2000.u
* @p9_proto_2000u: 9P2000.u extension
* @p9_proto_2010L: 9P2010.L extension
*/
enum p9_proto_versions{
p9_proto_legacy = 0,
p9_proto_2000u = 1,
p9_proto_2010L = 2,
};
/** /**
* enum p9_trans_status - different states of underlying transports * enum p9_trans_status - different states of underlying transports
* @Connected: transport is connected and healthy * @Connected: transport is connected and healthy
@ -111,6 +124,7 @@ struct p9_req_t {
* @lock: protect @fidlist * @lock: protect @fidlist
* @msize: maximum data size negotiated by protocol * @msize: maximum data size negotiated by protocol
* @dotu: extension flags negotiated by protocol * @dotu: extension flags negotiated by protocol
* @proto_version: 9P protocol version to use
* @trans_mod: module API instantiated with this client * @trans_mod: module API instantiated with this client
* @trans: tranport instance state and API * @trans: tranport instance state and API
* @conn: connection state information used by trans_fd * @conn: connection state information used by trans_fd
@ -137,7 +151,7 @@ struct p9_req_t {
struct p9_client { struct p9_client {
spinlock_t lock; /* protect client structure */ spinlock_t lock; /* protect client structure */
int msize; int msize;
unsigned char dotu; unsigned char proto_version;
struct p9_trans_module *trans_mod; struct p9_trans_module *trans_mod;
enum p9_trans_status status; enum p9_trans_status status;
void *trans; void *trans;
@ -209,5 +223,7 @@ int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int);
int p9stat_read(char *, int, struct p9_wstat *, int); int p9stat_read(char *, int, struct p9_wstat *, int);
void p9stat_free(struct p9_wstat *); void p9stat_free(struct p9_wstat *);
int p9_is_proto_dotu(struct p9_client *clnt);
int p9_is_proto_dotl(struct p9_client *clnt);
#endif /* NET_9P_CLIENT_H */ #endif /* NET_9P_CLIENT_H */

View File

@ -46,6 +46,7 @@ enum {
Opt_msize, Opt_msize,
Opt_trans, Opt_trans,
Opt_legacy, Opt_legacy,
Opt_version,
Opt_err, Opt_err,
}; };
@ -53,9 +54,42 @@ static const match_table_t tokens = {
{Opt_msize, "msize=%u"}, {Opt_msize, "msize=%u"},
{Opt_legacy, "noextend"}, {Opt_legacy, "noextend"},
{Opt_trans, "trans=%s"}, {Opt_trans, "trans=%s"},
{Opt_version, "version=%s"},
{Opt_err, NULL}, {Opt_err, NULL},
}; };
inline int p9_is_proto_dotl(struct p9_client *clnt)
{
return (clnt->proto_version == p9_proto_2010L);
}
EXPORT_SYMBOL(p9_is_proto_dotl);
inline int p9_is_proto_dotu(struct p9_client *clnt)
{
return (clnt->proto_version == p9_proto_2000u);
}
EXPORT_SYMBOL(p9_is_proto_dotu);
/* Interpret mount option for protocol version */
static unsigned char get_protocol_version(const substring_t *name)
{
unsigned char version = -EINVAL;
if (!strncmp("9p2000", name->from, name->to-name->from)) {
version = p9_proto_legacy;
P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n");
} else if (!strncmp("9p2000.u", name->from, name->to-name->from)) {
version = p9_proto_2000u;
P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
} else if (!strncmp("9p2010.L", name->from, name->to-name->from)) {
version = p9_proto_2010L;
P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2010.L\n");
} else {
P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ",
name->from);
}
return version;
}
static struct p9_req_t * static struct p9_req_t *
p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
@ -75,7 +109,7 @@ static int parse_opts(char *opts, struct p9_client *clnt)
int option; int option;
int ret = 0; int ret = 0;
clnt->dotu = 1; clnt->proto_version = p9_proto_2000u;
clnt->msize = 8192; clnt->msize = 8192;
if (!opts) if (!opts)
@ -118,7 +152,13 @@ static int parse_opts(char *opts, struct p9_client *clnt)
} }
break; break;
case Opt_legacy: case Opt_legacy:
clnt->dotu = 0; clnt->proto_version = p9_proto_legacy;
break;
case Opt_version:
ret = get_protocol_version(&args[0]);
if (ret == -EINVAL)
goto free_and_return;
clnt->proto_version = ret;
break; break;
default: default:
continue; continue;
@ -410,14 +450,15 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
int ecode; int ecode;
char *ename; char *ename;
err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); err = p9pdu_readf(req->rc, c->proto_version, "s?d",
&ename, &ecode);
if (err) { if (err) {
P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
err); err);
return err; return err;
} }
if (c->dotu) if (p9_is_proto_dotu(c))
err = -ecode; err = -ecode;
if (!err || !IS_ERR_VALUE(err)) if (!err || !IS_ERR_VALUE(err))
@ -515,7 +556,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
/* marshall the data */ /* marshall the data */
p9pdu_prepare(req->tc, tag, type); p9pdu_prepare(req->tc, tag, type);
va_start(ap, fmt); va_start(ap, fmt);
err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap); err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
va_end(ap); va_end(ap);
p9pdu_finalize(req->tc); p9pdu_finalize(req->tc);
@ -627,14 +668,31 @@ int p9_client_version(struct p9_client *c)
char *version; char *version;
int msize; int msize;
P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
c->msize, c->dotu); c->msize, c->proto_version);
req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize,
c->dotu ? "9P2000.u" : "9P2000"); switch (c->proto_version) {
case p9_proto_2010L:
req = p9_client_rpc(c, P9_TVERSION, "ds",
c->msize, "9P2010.L");
break;
case p9_proto_2000u:
req = p9_client_rpc(c, P9_TVERSION, "ds",
c->msize, "9P2000.u");
break;
case p9_proto_legacy:
req = p9_client_rpc(c, P9_TVERSION, "ds",
c->msize, "9P2000");
break;
default:
return -EINVAL;
break;
}
if (IS_ERR(req)) if (IS_ERR(req))
return PTR_ERR(req); return PTR_ERR(req);
err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
if (err) { if (err) {
P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
p9pdu_dump(1, req->rc); p9pdu_dump(1, req->rc);
@ -642,10 +700,12 @@ int p9_client_version(struct p9_client *c)
} }
P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
if (!memcmp(version, "9P2000.u", 8)) if (!strncmp(version, "9P2010.L", 8))
c->dotu = 1; c->proto_version = p9_proto_2010L;
else if (!memcmp(version, "9P2000", 6)) else if (!strncmp(version, "9P2000.u", 8))
c->dotu = 0; c->proto_version = p9_proto_2000u;
else if (!strncmp(version, "9P2000", 6))
c->proto_version = p9_proto_legacy;
else { else {
err = -EREMOTEIO; err = -EREMOTEIO;
goto error; goto error;
@ -700,8 +760,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
goto put_trans; goto put_trans;
} }
P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n", P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
clnt, clnt->trans_mod, clnt->msize, clnt->dotu); clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
err = clnt->trans_mod->create(clnt, dev_name, options); err = clnt->trans_mod->create(clnt, dev_name, options);
if (err) if (err)
@ -784,7 +844,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
goto error; goto error;
} }
err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
if (err) { if (err) {
p9pdu_dump(1, req->rc); p9pdu_dump(1, req->rc);
p9_free_req(clnt, req); p9_free_req(clnt, req);
@ -833,7 +893,7 @@ p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
goto error; goto error;
} }
err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
if (err) { if (err) {
p9pdu_dump(1, req->rc); p9pdu_dump(1, req->rc);
p9_free_req(clnt, req); p9_free_req(clnt, req);
@ -891,7 +951,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
goto error; goto error;
} }
err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
if (err) { if (err) {
p9pdu_dump(1, req->rc); p9pdu_dump(1, req->rc);
p9_free_req(clnt, req); p9_free_req(clnt, req);
@ -952,7 +1012,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
goto error; goto error;
} }
err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
if (err) { if (err) {
p9pdu_dump(1, req->rc); p9pdu_dump(1, req->rc);
goto free_and_error; goto free_and_error;
@ -997,7 +1057,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
goto error; goto error;
} }
err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
if (err) { if (err) {
p9pdu_dump(1, req->rc); p9pdu_dump(1, req->rc);
goto free_and_error; goto free_and_error;
@ -1098,7 +1158,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
goto error; goto error;
} }
err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
if (err) { if (err) {
p9pdu_dump(1, req->rc); p9pdu_dump(1, req->rc);
goto free_and_error; goto free_and_error;
@ -1159,7 +1219,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
goto error; goto error;
} }
err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
if (err) { if (err) {
p9pdu_dump(1, req->rc); p9pdu_dump(1, req->rc);
goto free_and_error; goto free_and_error;
@ -1199,7 +1259,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
goto error; goto error;
} }
err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
if (err) { if (err) {
p9pdu_dump(1, req->rc); p9pdu_dump(1, req->rc);
p9_free_req(clnt, req); p9_free_req(clnt, req);
@ -1226,7 +1286,7 @@ error:
} }
EXPORT_SYMBOL(p9_client_stat); EXPORT_SYMBOL(p9_client_stat);
static int p9_client_statsize(struct p9_wstat *wst, int optional) static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
{ {
int ret; int ret;
@ -1245,7 +1305,7 @@ static int p9_client_statsize(struct p9_wstat *wst, int optional)
if (wst->muid) if (wst->muid)
ret += strlen(wst->muid); ret += strlen(wst->muid);
if (optional) { if (proto_version == p9_proto_2000u) {
ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */ ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
if (wst->extension) if (wst->extension)
ret += strlen(wst->extension); ret += strlen(wst->extension);
@ -1262,7 +1322,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
err = 0; err = 0;
clnt = fid->clnt; clnt = fid->clnt;
wst->size = p9_client_statsize(wst, clnt->dotu); wst->size = p9_client_statsize(wst, clnt->proto_version);
P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
P9_DPRINTK(P9_DEBUG_9P, P9_DPRINTK(P9_DEBUG_9P,
" sz=%x type=%x dev=%x qid=%x.%llx.%x\n" " sz=%x type=%x dev=%x qid=%x.%llx.%x\n"

View File

@ -52,7 +52,7 @@
#endif #endif
static int static int
p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
#ifdef CONFIG_NET_9P_DEBUG #ifdef CONFIG_NET_9P_DEBUG
void void
@ -144,7 +144,8 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
*/ */
static int static int
p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
va_list ap)
{ {
const char *ptr; const char *ptr;
int errcode = 0; int errcode = 0;
@ -194,7 +195,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
int16_t len; int16_t len;
int size; int size;
errcode = p9pdu_readf(pdu, optional, "w", &len); errcode = p9pdu_readf(pdu, proto_version,
"w", &len);
if (errcode) if (errcode)
break; break;
@ -217,7 +219,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
struct p9_qid *qid = struct p9_qid *qid =
va_arg(ap, struct p9_qid *); va_arg(ap, struct p9_qid *);
errcode = p9pdu_readf(pdu, optional, "bdq", errcode = p9pdu_readf(pdu, proto_version, "bdq",
&qid->type, &qid->version, &qid->type, &qid->version,
&qid->path); &qid->path);
} }
@ -230,7 +232,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
-1; -1;
errcode = errcode =
p9pdu_readf(pdu, optional, p9pdu_readf(pdu, proto_version,
"wwdQdddqssss?sddd", "wwdQdddqssss?sddd",
&stbuf->size, &stbuf->type, &stbuf->size, &stbuf->type,
&stbuf->dev, &stbuf->qid, &stbuf->dev, &stbuf->qid,
@ -250,7 +252,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
void **data = va_arg(ap, void **); void **data = va_arg(ap, void **);
errcode = errcode =
p9pdu_readf(pdu, optional, "d", count); p9pdu_readf(pdu, proto_version, "d", count);
if (!errcode) { if (!errcode) {
*count = *count =
MIN(*count, MIN(*count,
@ -263,8 +265,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
int16_t *nwname = va_arg(ap, int16_t *); int16_t *nwname = va_arg(ap, int16_t *);
char ***wnames = va_arg(ap, char ***); char ***wnames = va_arg(ap, char ***);
errcode = errcode = p9pdu_readf(pdu, proto_version,
p9pdu_readf(pdu, optional, "w", nwname); "w", nwname);
if (!errcode) { if (!errcode) {
*wnames = *wnames =
kmalloc(sizeof(char *) * *nwname, kmalloc(sizeof(char *) * *nwname,
@ -278,7 +280,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
for (i = 0; i < *nwname; i++) { for (i = 0; i < *nwname; i++) {
errcode = errcode =
p9pdu_readf(pdu, optional, p9pdu_readf(pdu,
proto_version,
"s", "s",
&(*wnames)[i]); &(*wnames)[i]);
if (errcode) if (errcode)
@ -306,7 +309,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
*wqids = NULL; *wqids = NULL;
errcode = errcode =
p9pdu_readf(pdu, optional, "w", nwqid); p9pdu_readf(pdu, proto_version, "w", nwqid);
if (!errcode) { if (!errcode) {
*wqids = *wqids =
kmalloc(*nwqid * kmalloc(*nwqid *
@ -321,7 +324,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
for (i = 0; i < *nwqid; i++) { for (i = 0; i < *nwqid; i++) {
errcode = errcode =
p9pdu_readf(pdu, optional, p9pdu_readf(pdu,
proto_version,
"Q", "Q",
&(*wqids)[i]); &(*wqids)[i]);
if (errcode) if (errcode)
@ -336,7 +340,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
} }
break; break;
case '?': case '?':
if (!optional) if (proto_version != p9_proto_2000u)
return 0; return 0;
break; break;
default: default:
@ -352,7 +356,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
} }
int int
p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
va_list ap)
{ {
const char *ptr; const char *ptr;
int errcode = 0; int errcode = 0;
@ -389,7 +394,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
if (sptr) if (sptr)
len = MIN(strlen(sptr), USHORT_MAX); len = MIN(strlen(sptr), USHORT_MAX);
errcode = p9pdu_writef(pdu, optional, "w", len); errcode = p9pdu_writef(pdu, proto_version,
"w", len);
if (!errcode && pdu_write(pdu, sptr, len)) if (!errcode && pdu_write(pdu, sptr, len))
errcode = -EFAULT; errcode = -EFAULT;
} }
@ -398,7 +404,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
const struct p9_qid *qid = const struct p9_qid *qid =
va_arg(ap, const struct p9_qid *); va_arg(ap, const struct p9_qid *);
errcode = errcode =
p9pdu_writef(pdu, optional, "bdq", p9pdu_writef(pdu, proto_version, "bdq",
qid->type, qid->version, qid->type, qid->version,
qid->path); qid->path);
} break; } break;
@ -406,7 +412,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
const struct p9_wstat *stbuf = const struct p9_wstat *stbuf =
va_arg(ap, const struct p9_wstat *); va_arg(ap, const struct p9_wstat *);
errcode = errcode =
p9pdu_writef(pdu, optional, p9pdu_writef(pdu, proto_version,
"wwdQdddqssss?sddd", "wwdQdddqssss?sddd",
stbuf->size, stbuf->type, stbuf->size, stbuf->type,
stbuf->dev, &stbuf->qid, stbuf->dev, &stbuf->qid,
@ -421,8 +427,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
int32_t count = va_arg(ap, int32_t); int32_t count = va_arg(ap, int32_t);
const void *data = va_arg(ap, const void *); const void *data = va_arg(ap, const void *);
errcode = errcode = p9pdu_writef(pdu, proto_version, "d",
p9pdu_writef(pdu, optional, "d", count); count);
if (!errcode && pdu_write(pdu, data, count)) if (!errcode && pdu_write(pdu, data, count))
errcode = -EFAULT; errcode = -EFAULT;
} }
@ -431,8 +437,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
int32_t count = va_arg(ap, int32_t); int32_t count = va_arg(ap, int32_t);
const char __user *udata = const char __user *udata =
va_arg(ap, const void __user *); va_arg(ap, const void __user *);
errcode = errcode = p9pdu_writef(pdu, proto_version, "d",
p9pdu_writef(pdu, optional, "d", count); count);
if (!errcode && pdu_write_u(pdu, udata, count)) if (!errcode && pdu_write_u(pdu, udata, count))
errcode = -EFAULT; errcode = -EFAULT;
} }
@ -441,14 +447,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
int16_t nwname = va_arg(ap, int); int16_t nwname = va_arg(ap, int);
const char **wnames = va_arg(ap, const char **); const char **wnames = va_arg(ap, const char **);
errcode = errcode = p9pdu_writef(pdu, proto_version, "w",
p9pdu_writef(pdu, optional, "w", nwname); nwname);
if (!errcode) { if (!errcode) {
int i; int i;
for (i = 0; i < nwname; i++) { for (i = 0; i < nwname; i++) {
errcode = errcode =
p9pdu_writef(pdu, optional, p9pdu_writef(pdu,
proto_version,
"s", "s",
wnames[i]); wnames[i]);
if (errcode) if (errcode)
@ -462,14 +469,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
struct p9_qid *wqids = struct p9_qid *wqids =
va_arg(ap, struct p9_qid *); va_arg(ap, struct p9_qid *);
errcode = errcode = p9pdu_writef(pdu, proto_version, "w",
p9pdu_writef(pdu, optional, "w", nwqid); nwqid);
if (!errcode) { if (!errcode) {
int i; int i;
for (i = 0; i < nwqid; i++) { for (i = 0; i < nwqid; i++) {
errcode = errcode =
p9pdu_writef(pdu, optional, p9pdu_writef(pdu,
proto_version,
"Q", "Q",
&wqids[i]); &wqids[i]);
if (errcode) if (errcode)
@ -479,7 +487,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
} }
break; break;
case '?': case '?':
if (!optional) if (proto_version != p9_proto_2000u)
return 0; return 0;
break; break;
default: default:
@ -494,32 +502,32 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
return errcode; return errcode;
} }
int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...) int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
{ {
va_list ap; va_list ap;
int ret; int ret;
va_start(ap, fmt); va_start(ap, fmt);
ret = p9pdu_vreadf(pdu, optional, fmt, ap); ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
va_end(ap); va_end(ap);
return ret; return ret;
} }
static int static int
p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
{ {
va_list ap; va_list ap;
int ret; int ret;
va_start(ap, fmt); va_start(ap, fmt);
ret = p9pdu_vwritef(pdu, optional, fmt, ap); ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
va_end(ap); va_end(ap);
return ret; return ret;
} }
int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu) int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
{ {
struct p9_fcall fake_pdu; struct p9_fcall fake_pdu;
int ret; int ret;
@ -529,7 +537,7 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
fake_pdu.sdata = buf; fake_pdu.sdata = buf;
fake_pdu.offset = 0; fake_pdu.offset = 0;
ret = p9pdu_readf(&fake_pdu, dotu, "S", st); ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
if (ret) { if (ret) {
P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
p9pdu_dump(1, &fake_pdu); p9pdu_dump(1, &fake_pdu);

View File

@ -25,9 +25,9 @@
* *
*/ */
int int p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap); va_list ap);
int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...); int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type); int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type);
int p9pdu_finalize(struct p9_fcall *pdu); int p9pdu_finalize(struct p9_fcall *pdu);
void p9pdu_dump(int, struct p9_fcall *); void p9pdu_dump(int, struct p9_fcall *);

View File

@ -49,8 +49,6 @@
/* a single mutex to manage channel initialization and attachment */ /* a single mutex to manage channel initialization and attachment */
static DEFINE_MUTEX(virtio_9p_lock); static DEFINE_MUTEX(virtio_9p_lock);
/* global which tracks highest initialized channel */
static int chan_index;
/** /**
* struct virtio_chan - per-instance transport information * struct virtio_chan - per-instance transport information
@ -68,8 +66,7 @@ static int chan_index;
* *
*/ */
static struct virtio_chan { struct virtio_chan {
bool initialized;
bool inuse; bool inuse;
spinlock_t lock; spinlock_t lock;
@ -80,7 +77,11 @@ static struct virtio_chan {
/* Scatterlist: can be too big for stack. */ /* Scatterlist: can be too big for stack. */
struct scatterlist sg[VIRTQUEUE_NUM]; struct scatterlist sg[VIRTQUEUE_NUM];
} channels[MAX_9P_CHAN];
struct list_head chan_list;
};
static struct list_head virtio_chan_list;
/* How many bytes left in this page. */ /* How many bytes left in this page. */
static unsigned int rest_of_page(void *data) static unsigned int rest_of_page(void *data)
@ -217,9 +218,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
* p9_virtio_probe - probe for existence of 9P virtio channels * p9_virtio_probe - probe for existence of 9P virtio channels
* @vdev: virtio device to probe * @vdev: virtio device to probe
* *
* This probes for existing virtio channels. At present only * This probes for existing virtio channels.
* a single channel is in use, so in the future more work may need
* to be done here.
* *
*/ */
@ -227,16 +226,10 @@ static int p9_virtio_probe(struct virtio_device *vdev)
{ {
int err; int err;
struct virtio_chan *chan; struct virtio_chan *chan;
int index;
mutex_lock(&virtio_9p_lock); chan = kmalloc(sizeof(struct virtio_chan), GFP_KERNEL);
index = chan_index++; if (!chan) {
chan = &channels[index]; printk(KERN_ERR "9p: Failed to allocate virtio 9P channel\n");
mutex_unlock(&virtio_9p_lock);
if (chan_index > MAX_9P_CHAN) {
printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
BUG();
err = -ENOMEM; err = -ENOMEM;
goto fail; goto fail;
} }
@ -255,15 +248,15 @@ static int p9_virtio_probe(struct virtio_device *vdev)
sg_init_table(chan->sg, VIRTQUEUE_NUM); sg_init_table(chan->sg, VIRTQUEUE_NUM);
chan->inuse = false; chan->inuse = false;
chan->initialized = true; mutex_lock(&virtio_9p_lock);
list_add_tail(&chan->chan_list, &virtio_chan_list);
mutex_unlock(&virtio_9p_lock);
return 0; return 0;
out_free_vq: out_free_vq:
vdev->config->del_vqs(vdev); vdev->config->del_vqs(vdev);
kfree(chan);
fail: fail:
mutex_lock(&virtio_9p_lock);
chan_index--;
mutex_unlock(&virtio_9p_lock);
return err; return err;
} }
@ -280,35 +273,31 @@ fail:
* We use a simple reference count mechanism to ensure that only a single * We use a simple reference count mechanism to ensure that only a single
* mount has a channel open at a time. * mount has a channel open at a time.
* *
* Bugs: doesn't allow identification of a specific channel
* to allocate, channels are allocated sequentially. This was
* a pragmatic decision to get things rolling, but ideally some
* way of identifying the channel to attach to would be nice
* if we are going to support multiple channels.
*
*/ */
static int static int
p9_virtio_create(struct p9_client *client, const char *devname, char *args) p9_virtio_create(struct p9_client *client, const char *devname, char *args)
{ {
struct virtio_chan *chan = channels; struct virtio_chan *chan;
int index = 0; int ret = -ENOENT;
int found = 0;
mutex_lock(&virtio_9p_lock); mutex_lock(&virtio_9p_lock);
while (index < MAX_9P_CHAN) { list_for_each_entry(chan, &virtio_chan_list, chan_list) {
if (chan->initialized && !chan->inuse) { if (!strcmp(devname, dev_name(&chan->vdev->dev))) {
chan->inuse = true; if (!chan->inuse) {
break; chan->inuse = true;
} else { found = 1;
index++; break;
chan = &channels[index]; }
ret = -EBUSY;
} }
} }
mutex_unlock(&virtio_9p_lock); mutex_unlock(&virtio_9p_lock);
if (index >= MAX_9P_CHAN) { if (!found) {
printk(KERN_ERR "9p: no channels available\n"); printk(KERN_ERR "9p: no channels available\n");
return -ENODEV; return ret;
} }
client->trans = (void *)chan; client->trans = (void *)chan;
@ -329,11 +318,13 @@ static void p9_virtio_remove(struct virtio_device *vdev)
struct virtio_chan *chan = vdev->priv; struct virtio_chan *chan = vdev->priv;
BUG_ON(chan->inuse); BUG_ON(chan->inuse);
vdev->config->del_vqs(vdev);
mutex_lock(&virtio_9p_lock);
list_del(&chan->chan_list);
mutex_unlock(&virtio_9p_lock);
kfree(chan);
if (chan->initialized) {
vdev->config->del_vqs(vdev);
chan->initialized = false;
}
} }
static struct virtio_device_id id_table[] = { static struct virtio_device_id id_table[] = {
@ -364,10 +355,7 @@ static struct p9_trans_module p9_virtio_trans = {
/* The standard init function */ /* The standard init function */
static int __init p9_virtio_init(void) static int __init p9_virtio_init(void)
{ {
int count; INIT_LIST_HEAD(&virtio_chan_list);
for (count = 0; count < MAX_9P_CHAN; count++)
channels[count].initialized = false;
v9fs_register_trans(&p9_virtio_trans); v9fs_register_trans(&p9_virtio_trans);
return register_virtio_driver(&p9_virtio_drv); return register_virtio_driver(&p9_virtio_drv);