aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-03-05 16:25:24 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-05 16:25:24 -0500
commitb13d3c6e8ab6ac53e8c1858a9c837cb6ba3bbef0 (patch)
tree4c0b6cba4975b0d7871096e0a99406d450b0272f
parente213e26ab3988c516c06eba4dcd030ac052f6dc9 (diff)
parent5717144a01d701614cfdb15f09ed562d720cf3db (diff)
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.
-rw-r--r--fs/9p/fid.c2
-rw-r--r--fs/9p/v9fs.c8
-rw-r--r--fs/9p/v9fs.h23
-rw-r--r--fs/9p/vfs_dir.c2
-rw-r--r--fs/9p/vfs_file.c4
-rw-r--r--fs/9p/vfs_inode.c48
-rw-r--r--include/linux/virtio_9p.h3
-rw-r--r--include/net/9p/client.h18
-rw-r--r--net/9p/client.c114
-rw-r--r--net/9p/protocol.c74
-rw-r--r--net/9p/protocol.h6
-rw-r--r--net/9p/trans_virtio.c80
12 files changed, 238 insertions, 144 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 14d944204571..08b2eb157048 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -151,7 +151,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
151 if (access == V9FS_ACCESS_SINGLE) 151 if (access == V9FS_ACCESS_SINGLE)
152 return ERR_PTR(-EPERM); 152 return ERR_PTR(-EPERM);
153 153
154 if (v9fs_extended(v9ses)) 154 if (v9fs_proto_dotu(v9ses))
155 uname = NULL; 155 uname = NULL;
156 else 156 else
157 uname = v9ses->uname; 157 uname = v9ses->uname;
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 7d6c2139891d..6c7f6a251115 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -241,7 +241,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
241 list_add(&v9ses->slist, &v9fs_sessionlist); 241 list_add(&v9ses->slist, &v9fs_sessionlist);
242 spin_unlock(&v9fs_sessionlist_lock); 242 spin_unlock(&v9fs_sessionlist_lock);
243 243
244 v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER; 244 v9ses->flags = V9FS_PROTO_2000U | V9FS_ACCESS_USER;
245 strcpy(v9ses->uname, V9FS_DEFUSER); 245 strcpy(v9ses->uname, V9FS_DEFUSER);
246 strcpy(v9ses->aname, V9FS_DEFANAME); 246 strcpy(v9ses->aname, V9FS_DEFANAME);
247 v9ses->uid = ~0; 247 v9ses->uid = ~0;
@@ -262,13 +262,13 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
262 goto error; 262 goto error;
263 } 263 }
264 264
265 if (!v9ses->clnt->dotu) 265 if (!p9_is_proto_dotu(v9ses->clnt))
266 v9ses->flags &= ~V9FS_EXTENDED; 266 v9ses->flags &= ~V9FS_PROTO_2000U;
267 267
268 v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; 268 v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
269 269
270 /* for legacy mode, fall back to V9FS_ACCESS_ANY */ 270 /* for legacy mode, fall back to V9FS_ACCESS_ANY */
271 if (!v9fs_extended(v9ses) && 271 if (!v9fs_proto_dotu(v9ses) &&
272 ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) { 272 ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
273 273
274 v9ses->flags &= ~V9FS_ACCESS_MASK; 274 v9ses->flags &= ~V9FS_ACCESS_MASK;
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 019f4ccb70c1..79000bf62491 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -23,7 +23,8 @@
23 23
24/** 24/**
25 * enum p9_session_flags - option flags for each 9P session 25 * enum p9_session_flags - option flags for each 9P session
26 * @V9FS_EXTENDED: whether or not to use 9P2000.u extensions 26 * @V9FS_PROTO_2000U: whether or not to use 9P2000.u extensions
27 * @V9FS_PROTO_2010L: whether or not to use 9P2010.l extensions
27 * @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy 28 * @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy
28 * @V9FS_ACCESS_USER: a new attach will be issued for every user (default) 29 * @V9FS_ACCESS_USER: a new attach will be issued for every user (default)
29 * @V9FS_ACCESS_ANY: use a single attach for all users 30 * @V9FS_ACCESS_ANY: use a single attach for all users
@@ -32,11 +33,12 @@
32 * Session flags reflect options selected by users at mount time 33 * Session flags reflect options selected by users at mount time
33 */ 34 */
34enum p9_session_flags { 35enum p9_session_flags {
35 V9FS_EXTENDED = 0x01, 36 V9FS_PROTO_2000U = 0x01,
36 V9FS_ACCESS_SINGLE = 0x02, 37 V9FS_PROTO_2010L = 0x02,
37 V9FS_ACCESS_USER = 0x04, 38 V9FS_ACCESS_SINGLE = 0x04,
38 V9FS_ACCESS_ANY = 0x06, 39 V9FS_ACCESS_USER = 0x08,
39 V9FS_ACCESS_MASK = 0x06, 40 V9FS_ACCESS_ANY = 0x0C,
41 V9FS_ACCESS_MASK = 0x0C,
40}; 42};
41 43
42/* possible values of ->cache */ 44/* possible values of ->cache */
@@ -121,7 +123,12 @@ static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
121 return (inode->i_sb->s_fs_info); 123 return (inode->i_sb->s_fs_info);
122} 124}
123 125
124static inline int v9fs_extended(struct v9fs_session_info *v9ses) 126static inline int v9fs_proto_dotu(struct v9fs_session_info *v9ses)
125{ 127{
126 return v9ses->flags & V9FS_EXTENDED; 128 return v9ses->flags & V9FS_PROTO_2000U;
129}
130
131static inline int v9fs_proto_dotl(struct v9fs_session_info *v9ses)
132{
133 return v9ses->flags & V9FS_PROTO_2010L;
127} 134}
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 15cce53bf61e..6580aa449541 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -135,7 +135,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
135 while (rdir->head < rdir->tail) { 135 while (rdir->head < rdir->tail) {
136 err = p9stat_read(rdir->buf + rdir->head, 136 err = p9stat_read(rdir->buf + rdir->head,
137 buflen - rdir->head, &st, 137 buflen - rdir->head, &st,
138 fid->clnt->dotu); 138 fid->clnt->proto_version);
139 if (err) { 139 if (err) {
140 P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); 140 P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
141 err = -EIO; 141 err = -EIO;
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 74a0461a9ac0..36122683fae8 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -61,7 +61,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
61 61
62 P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file); 62 P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
63 v9ses = v9fs_inode2v9ses(inode); 63 v9ses = v9fs_inode2v9ses(inode);
64 omode = v9fs_uflags2omode(file->f_flags, v9fs_extended(v9ses)); 64 omode = v9fs_uflags2omode(file->f_flags, v9fs_proto_dotu(v9ses));
65 fid = file->private_data; 65 fid = file->private_data;
66 if (!fid) { 66 if (!fid) {
67 fid = v9fs_fid_clone(file->f_path.dentry); 67 fid = v9fs_fid_clone(file->f_path.dentry);
@@ -77,7 +77,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
77 i_size_write(inode, 0); 77 i_size_write(inode, 0);
78 inode->i_blocks = 0; 78 inode->i_blocks = 0;
79 } 79 }
80 if ((file->f_flags & O_APPEND) && (!v9fs_extended(v9ses))) 80 if ((file->f_flags & O_APPEND) && (!v9fs_proto_dotu(v9ses)))
81 generic_file_llseek(file, 0, SEEK_END); 81 generic_file_llseek(file, 0, SEEK_END);
82 } 82 }
83 83
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index a407fa3388c0..5fe45d692c9f 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -60,7 +60,7 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
60 res = mode & 0777; 60 res = mode & 0777;
61 if (S_ISDIR(mode)) 61 if (S_ISDIR(mode))
62 res |= P9_DMDIR; 62 res |= P9_DMDIR;
63 if (v9fs_extended(v9ses)) { 63 if (v9fs_proto_dotu(v9ses)) {
64 if (S_ISLNK(mode)) 64 if (S_ISLNK(mode))
65 res |= P9_DMSYMLINK; 65 res |= P9_DMSYMLINK;
66 if (v9ses->nodev == 0) { 66 if (v9ses->nodev == 0) {
@@ -102,21 +102,21 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
102 102
103 if ((mode & P9_DMDIR) == P9_DMDIR) 103 if ((mode & P9_DMDIR) == P9_DMDIR)
104 res |= S_IFDIR; 104 res |= S_IFDIR;
105 else if ((mode & P9_DMSYMLINK) && (v9fs_extended(v9ses))) 105 else if ((mode & P9_DMSYMLINK) && (v9fs_proto_dotu(v9ses)))
106 res |= S_IFLNK; 106 res |= S_IFLNK;
107 else if ((mode & P9_DMSOCKET) && (v9fs_extended(v9ses)) 107 else if ((mode & P9_DMSOCKET) && (v9fs_proto_dotu(v9ses))
108 && (v9ses->nodev == 0)) 108 && (v9ses->nodev == 0))
109 res |= S_IFSOCK; 109 res |= S_IFSOCK;
110 else if ((mode & P9_DMNAMEDPIPE) && (v9fs_extended(v9ses)) 110 else if ((mode & P9_DMNAMEDPIPE) && (v9fs_proto_dotu(v9ses))
111 && (v9ses->nodev == 0)) 111 && (v9ses->nodev == 0))
112 res |= S_IFIFO; 112 res |= S_IFIFO;
113 else if ((mode & P9_DMDEVICE) && (v9fs_extended(v9ses)) 113 else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
114 && (v9ses->nodev == 0)) 114 && (v9ses->nodev == 0))
115 res |= S_IFBLK; 115 res |= S_IFBLK;
116 else 116 else
117 res |= S_IFREG; 117 res |= S_IFREG;
118 118
119 if (v9fs_extended(v9ses)) { 119 if (v9fs_proto_dotu(v9ses)) {
120 if ((mode & P9_DMSETUID) == P9_DMSETUID) 120 if ((mode & P9_DMSETUID) == P9_DMSETUID)
121 res |= S_ISUID; 121 res |= S_ISUID;
122 122
@@ -265,7 +265,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
265 case S_IFBLK: 265 case S_IFBLK:
266 case S_IFCHR: 266 case S_IFCHR:
267 case S_IFSOCK: 267 case S_IFSOCK:
268 if (!v9fs_extended(v9ses)) { 268 if (!v9fs_proto_dotu(v9ses)) {
269 P9_DPRINTK(P9_DEBUG_ERROR, 269 P9_DPRINTK(P9_DEBUG_ERROR,
270 "special files without extended mode\n"); 270 "special files without extended mode\n");
271 err = -EINVAL; 271 err = -EINVAL;
@@ -278,7 +278,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
278 inode->i_fop = &v9fs_file_operations; 278 inode->i_fop = &v9fs_file_operations;
279 break; 279 break;
280 case S_IFLNK: 280 case S_IFLNK:
281 if (!v9fs_extended(v9ses)) { 281 if (!v9fs_proto_dotu(v9ses)) {
282 P9_DPRINTK(P9_DEBUG_ERROR, 282 P9_DPRINTK(P9_DEBUG_ERROR,
283 "extended modes used w/o 9P2000.u\n"); 283 "extended modes used w/o 9P2000.u\n");
284 err = -EINVAL; 284 err = -EINVAL;
@@ -288,7 +288,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
288 break; 288 break;
289 case S_IFDIR: 289 case S_IFDIR:
290 inc_nlink(inode); 290 inc_nlink(inode);
291 if (v9fs_extended(v9ses)) 291 if (v9fs_proto_dotu(v9ses))
292 inode->i_op = &v9fs_dir_inode_operations_ext; 292 inode->i_op = &v9fs_dir_inode_operations_ext;
293 else 293 else
294 inode->i_op = &v9fs_dir_inode_operations; 294 inode->i_op = &v9fs_dir_inode_operations;
@@ -575,7 +575,8 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
575 flags = O_RDWR; 575 flags = O_RDWR;
576 576
577 fid = v9fs_create(v9ses, dir, dentry, NULL, perm, 577 fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
578 v9fs_uflags2omode(flags, v9fs_extended(v9ses))); 578 v9fs_uflags2omode(flags,
579 v9fs_proto_dotu(v9ses)));
579 if (IS_ERR(fid)) { 580 if (IS_ERR(fid)) {
580 err = PTR_ERR(fid); 581 err = PTR_ERR(fid);
581 fid = NULL; 582 fid = NULL;
@@ -858,7 +859,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
858 if (iattr->ia_valid & ATTR_SIZE) 859 if (iattr->ia_valid & ATTR_SIZE)
859 wstat.length = iattr->ia_size; 860 wstat.length = iattr->ia_size;
860 861
861 if (v9fs_extended(v9ses)) { 862 if (v9fs_proto_dotu(v9ses)) {
862 if (iattr->ia_valid & ATTR_UID) 863 if (iattr->ia_valid & ATTR_UID)
863 wstat.n_uid = iattr->ia_uid; 864 wstat.n_uid = iattr->ia_uid;
864 865
@@ -886,6 +887,8 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
886 struct super_block *sb) 887 struct super_block *sb)
887{ 888{
888 char ext[32]; 889 char ext[32];
890 char tag_name[14];
891 unsigned int i_nlink;
889 struct v9fs_session_info *v9ses = sb->s_fs_info; 892 struct v9fs_session_info *v9ses = sb->s_fs_info;
890 893
891 inode->i_nlink = 1; 894 inode->i_nlink = 1;
@@ -897,11 +900,26 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
897 inode->i_uid = v9ses->dfltuid; 900 inode->i_uid = v9ses->dfltuid;
898 inode->i_gid = v9ses->dfltgid; 901 inode->i_gid = v9ses->dfltgid;
899 902
900 if (v9fs_extended(v9ses)) { 903 if (v9fs_proto_dotu(v9ses)) {
901 inode->i_uid = stat->n_uid; 904 inode->i_uid = stat->n_uid;
902 inode->i_gid = stat->n_gid; 905 inode->i_gid = stat->n_gid;
903 } 906 }
904 907 if ((S_ISREG(inode->i_mode)) || (S_ISDIR(inode->i_mode))) {
908 if (v9fs_proto_dotu(v9ses) && (stat->extension[0] != '\0')) {
909 /*
910 * Hadlink support got added later to
911 * to the .u extension. So there can be
912 * server out there that doesn't support
913 * this even with .u extension. So check
914 * for non NULL stat->extension
915 */
916 strncpy(ext, stat->extension, sizeof(ext));
917 /* HARDLINKCOUNT %u */
918 sscanf(ext, "%13s %u", tag_name, &i_nlink);
919 if (!strncmp(tag_name, "HARDLINKCOUNT", 13))
920 inode->i_nlink = i_nlink;
921 }
922 }
905 inode->i_mode = p9mode2unixmode(v9ses, stat->mode); 923 inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
906 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { 924 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
907 char type = 0; 925 char type = 0;
@@ -976,7 +994,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
976 if (IS_ERR(fid)) 994 if (IS_ERR(fid))
977 return PTR_ERR(fid); 995 return PTR_ERR(fid);
978 996
979 if (!v9fs_extended(v9ses)) 997 if (!v9fs_proto_dotu(v9ses))
980 return -EBADF; 998 return -EBADF;
981 999
982 st = p9_client_stat(fid); 1000 st = p9_client_stat(fid);
@@ -1066,7 +1084,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1066 struct p9_fid *fid; 1084 struct p9_fid *fid;
1067 1085
1068 v9ses = v9fs_inode2v9ses(dir); 1086 v9ses = v9fs_inode2v9ses(dir);
1069 if (!v9fs_extended(v9ses)) { 1087 if (!v9fs_proto_dotu(v9ses)) {
1070 P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); 1088 P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
1071 return -EPERM; 1089 return -EPERM;
1072 } 1090 }
diff --git a/include/linux/virtio_9p.h b/include/linux/virtio_9p.h
index 095e10d148b4..332275080083 100644
--- a/include/linux/virtio_9p.h
+++ b/include/linux/virtio_9p.h
@@ -5,7 +5,4 @@
5#include <linux/virtio_ids.h> 5#include <linux/virtio_ids.h>
6#include <linux/virtio_config.h> 6#include <linux/virtio_config.h>
7 7
8/* Maximum number of virtio channels per partition (1 for now) */
9#define MAX_9P_CHAN 1
10
11#endif /* _LINUX_VIRTIO_9P_H */ 8#endif /* _LINUX_VIRTIO_9P_H */
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index fb00b329f0d3..52e1fff709e4 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -29,6 +29,19 @@
29/* Number of requests per row */ 29/* Number of requests per row */
30#define P9_ROW_MAXTAG 255 30#define P9_ROW_MAXTAG 255
31 31
32/** enum p9_proto_versions - 9P protocol versions
33 * @p9_proto_legacy: 9P Legacy mode, pre-9P2000.u
34 * @p9_proto_2000u: 9P2000.u extension
35 * @p9_proto_2010L: 9P2010.L extension
36 */
37
38enum p9_proto_versions{
39 p9_proto_legacy = 0,
40 p9_proto_2000u = 1,
41 p9_proto_2010L = 2,
42};
43
44
32/** 45/**
33 * enum p9_trans_status - different states of underlying transports 46 * enum p9_trans_status - different states of underlying transports
34 * @Connected: transport is connected and healthy 47 * @Connected: transport is connected and healthy
@@ -111,6 +124,7 @@ struct p9_req_t {
111 * @lock: protect @fidlist 124 * @lock: protect @fidlist
112 * @msize: maximum data size negotiated by protocol 125 * @msize: maximum data size negotiated by protocol
113 * @dotu: extension flags negotiated by protocol 126 * @dotu: extension flags negotiated by protocol
127 * @proto_version: 9P protocol version to use
114 * @trans_mod: module API instantiated with this client 128 * @trans_mod: module API instantiated with this client
115 * @trans: tranport instance state and API 129 * @trans: tranport instance state and API
116 * @conn: connection state information used by trans_fd 130 * @conn: connection state information used by trans_fd
@@ -137,7 +151,7 @@ struct p9_req_t {
137struct p9_client { 151struct p9_client {
138 spinlock_t lock; /* protect client structure */ 152 spinlock_t lock; /* protect client structure */
139 int msize; 153 int msize;
140 unsigned char dotu; 154 unsigned char proto_version;
141 struct p9_trans_module *trans_mod; 155 struct p9_trans_module *trans_mod;
142 enum p9_trans_status status; 156 enum p9_trans_status status;
143 void *trans; 157 void *trans;
@@ -209,5 +223,7 @@ int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int);
209int p9stat_read(char *, int, struct p9_wstat *, int); 223int p9stat_read(char *, int, struct p9_wstat *, int);
210void p9stat_free(struct p9_wstat *); 224void p9stat_free(struct p9_wstat *);
211 225
226int p9_is_proto_dotu(struct p9_client *clnt);
227int p9_is_proto_dotl(struct p9_client *clnt);
212 228
213#endif /* NET_9P_CLIENT_H */ 229#endif /* NET_9P_CLIENT_H */
diff --git a/net/9p/client.c b/net/9p/client.c
index 09d4f1e2e4a8..bde9f3d38c57 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -46,6 +46,7 @@ enum {
46 Opt_msize, 46 Opt_msize,
47 Opt_trans, 47 Opt_trans,
48 Opt_legacy, 48 Opt_legacy,
49 Opt_version,
49 Opt_err, 50 Opt_err,
50}; 51};
51 52
@@ -53,9 +54,42 @@ static const match_table_t tokens = {
53 {Opt_msize, "msize=%u"}, 54 {Opt_msize, "msize=%u"},
54 {Opt_legacy, "noextend"}, 55 {Opt_legacy, "noextend"},
55 {Opt_trans, "trans=%s"}, 56 {Opt_trans, "trans=%s"},
57 {Opt_version, "version=%s"},
56 {Opt_err, NULL}, 58 {Opt_err, NULL},
57}; 59};
58 60
61inline int p9_is_proto_dotl(struct p9_client *clnt)
62{
63 return (clnt->proto_version == p9_proto_2010L);
64}
65EXPORT_SYMBOL(p9_is_proto_dotl);
66
67inline int p9_is_proto_dotu(struct p9_client *clnt)
68{
69 return (clnt->proto_version == p9_proto_2000u);
70}
71EXPORT_SYMBOL(p9_is_proto_dotu);
72
73/* Interpret mount option for protocol version */
74static unsigned char get_protocol_version(const substring_t *name)
75{
76 unsigned char version = -EINVAL;
77 if (!strncmp("9p2000", name->from, name->to-name->from)) {
78 version = p9_proto_legacy;
79 P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n");
80 } else if (!strncmp("9p2000.u", name->from, name->to-name->from)) {
81 version = p9_proto_2000u;
82 P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
83 } else if (!strncmp("9p2010.L", name->from, name->to-name->from)) {
84 version = p9_proto_2010L;
85 P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2010.L\n");
86 } else {
87 P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ",
88 name->from);
89 }
90 return version;
91}
92
59static struct p9_req_t * 93static struct p9_req_t *
60p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); 94p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
61 95
@@ -75,7 +109,7 @@ static int parse_opts(char *opts, struct p9_client *clnt)
75 int option; 109 int option;
76 int ret = 0; 110 int ret = 0;
77 111
78 clnt->dotu = 1; 112 clnt->proto_version = p9_proto_2000u;
79 clnt->msize = 8192; 113 clnt->msize = 8192;
80 114
81 if (!opts) 115 if (!opts)
@@ -118,7 +152,13 @@ static int parse_opts(char *opts, struct p9_client *clnt)
118 } 152 }
119 break; 153 break;
120 case Opt_legacy: 154 case Opt_legacy:
121 clnt->dotu = 0; 155 clnt->proto_version = p9_proto_legacy;
156 break;
157 case Opt_version:
158 ret = get_protocol_version(&args[0]);
159 if (ret == -EINVAL)
160 goto free_and_return;
161 clnt->proto_version = ret;
122 break; 162 break;
123 default: 163 default:
124 continue; 164 continue;
@@ -410,14 +450,15 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
410 int ecode; 450 int ecode;
411 char *ename; 451 char *ename;
412 452
413 err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); 453 err = p9pdu_readf(req->rc, c->proto_version, "s?d",
454 &ename, &ecode);
414 if (err) { 455 if (err) {
415 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", 456 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
416 err); 457 err);
417 return err; 458 return err;
418 } 459 }
419 460
420 if (c->dotu) 461 if (p9_is_proto_dotu(c))
421 err = -ecode; 462 err = -ecode;
422 463
423 if (!err || !IS_ERR_VALUE(err)) 464 if (!err || !IS_ERR_VALUE(err))
@@ -515,7 +556,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
515 /* marshall the data */ 556 /* marshall the data */
516 p9pdu_prepare(req->tc, tag, type); 557 p9pdu_prepare(req->tc, tag, type);
517 va_start(ap, fmt); 558 va_start(ap, fmt);
518 err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap); 559 err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
519 va_end(ap); 560 va_end(ap);
520 p9pdu_finalize(req->tc); 561 p9pdu_finalize(req->tc);
521 562
@@ -627,14 +668,31 @@ int p9_client_version(struct p9_client *c)
627 char *version; 668 char *version;
628 int msize; 669 int msize;
629 670
630 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", 671 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
631 c->msize, c->dotu); 672 c->msize, c->proto_version);
632 req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, 673
633 c->dotu ? "9P2000.u" : "9P2000"); 674 switch (c->proto_version) {
675 case p9_proto_2010L:
676 req = p9_client_rpc(c, P9_TVERSION, "ds",
677 c->msize, "9P2010.L");
678 break;
679 case p9_proto_2000u:
680 req = p9_client_rpc(c, P9_TVERSION, "ds",
681 c->msize, "9P2000.u");
682 break;
683 case p9_proto_legacy:
684 req = p9_client_rpc(c, P9_TVERSION, "ds",
685 c->msize, "9P2000");
686 break;
687 default:
688 return -EINVAL;
689 break;
690 }
691
634 if (IS_ERR(req)) 692 if (IS_ERR(req))
635 return PTR_ERR(req); 693 return PTR_ERR(req);
636 694
637 err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); 695 err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
638 if (err) { 696 if (err) {
639 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); 697 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
640 p9pdu_dump(1, req->rc); 698 p9pdu_dump(1, req->rc);
@@ -642,10 +700,12 @@ int p9_client_version(struct p9_client *c)
642 } 700 }
643 701
644 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); 702 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
645 if (!memcmp(version, "9P2000.u", 8)) 703 if (!strncmp(version, "9P2010.L", 8))
646 c->dotu = 1; 704 c->proto_version = p9_proto_2010L;
647 else if (!memcmp(version, "9P2000", 6)) 705 else if (!strncmp(version, "9P2000.u", 8))
648 c->dotu = 0; 706 c->proto_version = p9_proto_2000u;
707 else if (!strncmp(version, "9P2000", 6))
708 c->proto_version = p9_proto_legacy;
649 else { 709 else {
650 err = -EREMOTEIO; 710 err = -EREMOTEIO;
651 goto error; 711 goto error;
@@ -700,8 +760,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
700 goto put_trans; 760 goto put_trans;
701 } 761 }
702 762
703 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n", 763 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
704 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 764 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
705 765
706 err = clnt->trans_mod->create(clnt, dev_name, options); 766 err = clnt->trans_mod->create(clnt, dev_name, options);
707 if (err) 767 if (err)
@@ -784,7 +844,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
784 goto error; 844 goto error;
785 } 845 }
786 846
787 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 847 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
788 if (err) { 848 if (err) {
789 p9pdu_dump(1, req->rc); 849 p9pdu_dump(1, req->rc);
790 p9_free_req(clnt, req); 850 p9_free_req(clnt, req);
@@ -833,7 +893,7 @@ p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
833 goto error; 893 goto error;
834 } 894 }
835 895
836 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 896 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
837 if (err) { 897 if (err) {
838 p9pdu_dump(1, req->rc); 898 p9pdu_dump(1, req->rc);
839 p9_free_req(clnt, req); 899 p9_free_req(clnt, req);
@@ -891,7 +951,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
891 goto error; 951 goto error;
892 } 952 }
893 953
894 err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); 954 err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
895 if (err) { 955 if (err) {
896 p9pdu_dump(1, req->rc); 956 p9pdu_dump(1, req->rc);
897 p9_free_req(clnt, req); 957 p9_free_req(clnt, req);
@@ -952,7 +1012,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
952 goto error; 1012 goto error;
953 } 1013 }
954 1014
955 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1015 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
956 if (err) { 1016 if (err) {
957 p9pdu_dump(1, req->rc); 1017 p9pdu_dump(1, req->rc);
958 goto free_and_error; 1018 goto free_and_error;
@@ -997,7 +1057,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
997 goto error; 1057 goto error;
998 } 1058 }
999 1059
1000 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1060 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
1001 if (err) { 1061 if (err) {
1002 p9pdu_dump(1, req->rc); 1062 p9pdu_dump(1, req->rc);
1003 goto free_and_error; 1063 goto free_and_error;
@@ -1098,7 +1158,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
1098 goto error; 1158 goto error;
1099 } 1159 }
1100 1160
1101 err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); 1161 err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
1102 if (err) { 1162 if (err) {
1103 p9pdu_dump(1, req->rc); 1163 p9pdu_dump(1, req->rc);
1104 goto free_and_error; 1164 goto free_and_error;
@@ -1159,7 +1219,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
1159 goto error; 1219 goto error;
1160 } 1220 }
1161 1221
1162 err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); 1222 err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
1163 if (err) { 1223 if (err) {
1164 p9pdu_dump(1, req->rc); 1224 p9pdu_dump(1, req->rc);
1165 goto free_and_error; 1225 goto free_and_error;
@@ -1199,7 +1259,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
1199 goto error; 1259 goto error;
1200 } 1260 }
1201 1261
1202 err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); 1262 err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
1203 if (err) { 1263 if (err) {
1204 p9pdu_dump(1, req->rc); 1264 p9pdu_dump(1, req->rc);
1205 p9_free_req(clnt, req); 1265 p9_free_req(clnt, req);
@@ -1226,7 +1286,7 @@ error:
1226} 1286}
1227EXPORT_SYMBOL(p9_client_stat); 1287EXPORT_SYMBOL(p9_client_stat);
1228 1288
1229static int p9_client_statsize(struct p9_wstat *wst, int optional) 1289static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
1230{ 1290{
1231 int ret; 1291 int ret;
1232 1292
@@ -1245,7 +1305,7 @@ static int p9_client_statsize(struct p9_wstat *wst, int optional)
1245 if (wst->muid) 1305 if (wst->muid)
1246 ret += strlen(wst->muid); 1306 ret += strlen(wst->muid);
1247 1307
1248 if (optional) { 1308 if (proto_version == p9_proto_2000u) {
1249 ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */ 1309 ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
1250 if (wst->extension) 1310 if (wst->extension)
1251 ret += strlen(wst->extension); 1311 ret += strlen(wst->extension);
@@ -1262,7 +1322,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1262 1322
1263 err = 0; 1323 err = 0;
1264 clnt = fid->clnt; 1324 clnt = fid->clnt;
1265 wst->size = p9_client_statsize(wst, clnt->dotu); 1325 wst->size = p9_client_statsize(wst, clnt->proto_version);
1266 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); 1326 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
1267 P9_DPRINTK(P9_DEBUG_9P, 1327 P9_DPRINTK(P9_DEBUG_9P,
1268 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" 1328 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index fc70147c771e..94f5a8f65e9c 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -52,7 +52,7 @@
52#endif 52#endif
53 53
54static int 54static int
55p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); 55p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
56 56
57#ifdef CONFIG_NET_9P_DEBUG 57#ifdef CONFIG_NET_9P_DEBUG
58void 58void
@@ -144,7 +144,8 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
144*/ 144*/
145 145
146static int 146static int
147p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) 147p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
148 va_list ap)
148{ 149{
149 const char *ptr; 150 const char *ptr;
150 int errcode = 0; 151 int errcode = 0;
@@ -194,7 +195,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
194 int16_t len; 195 int16_t len;
195 int size; 196 int size;
196 197
197 errcode = p9pdu_readf(pdu, optional, "w", &len); 198 errcode = p9pdu_readf(pdu, proto_version,
199 "w", &len);
198 if (errcode) 200 if (errcode)
199 break; 201 break;
200 202
@@ -217,7 +219,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
217 struct p9_qid *qid = 219 struct p9_qid *qid =
218 va_arg(ap, struct p9_qid *); 220 va_arg(ap, struct p9_qid *);
219 221
220 errcode = p9pdu_readf(pdu, optional, "bdq", 222 errcode = p9pdu_readf(pdu, proto_version, "bdq",
221 &qid->type, &qid->version, 223 &qid->type, &qid->version,
222 &qid->path); 224 &qid->path);
223 } 225 }
@@ -230,7 +232,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
230 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = 232 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
231 -1; 233 -1;
232 errcode = 234 errcode =
233 p9pdu_readf(pdu, optional, 235 p9pdu_readf(pdu, proto_version,
234 "wwdQdddqssss?sddd", 236 "wwdQdddqssss?sddd",
235 &stbuf->size, &stbuf->type, 237 &stbuf->size, &stbuf->type,
236 &stbuf->dev, &stbuf->qid, 238 &stbuf->dev, &stbuf->qid,
@@ -250,7 +252,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
250 void **data = va_arg(ap, void **); 252 void **data = va_arg(ap, void **);
251 253
252 errcode = 254 errcode =
253 p9pdu_readf(pdu, optional, "d", count); 255 p9pdu_readf(pdu, proto_version, "d", count);
254 if (!errcode) { 256 if (!errcode) {
255 *count = 257 *count =
256 MIN(*count, 258 MIN(*count,
@@ -263,8 +265,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
263 int16_t *nwname = va_arg(ap, int16_t *); 265 int16_t *nwname = va_arg(ap, int16_t *);
264 char ***wnames = va_arg(ap, char ***); 266 char ***wnames = va_arg(ap, char ***);
265 267
266 errcode = 268 errcode = p9pdu_readf(pdu, proto_version,
267 p9pdu_readf(pdu, optional, "w", nwname); 269 "w", nwname);
268 if (!errcode) { 270 if (!errcode) {
269 *wnames = 271 *wnames =
270 kmalloc(sizeof(char *) * *nwname, 272 kmalloc(sizeof(char *) * *nwname,
@@ -278,7 +280,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
278 280
279 for (i = 0; i < *nwname; i++) { 281 for (i = 0; i < *nwname; i++) {
280 errcode = 282 errcode =
281 p9pdu_readf(pdu, optional, 283 p9pdu_readf(pdu,
284 proto_version,
282 "s", 285 "s",
283 &(*wnames)[i]); 286 &(*wnames)[i]);
284 if (errcode) 287 if (errcode)
@@ -306,7 +309,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
306 *wqids = NULL; 309 *wqids = NULL;
307 310
308 errcode = 311 errcode =
309 p9pdu_readf(pdu, optional, "w", nwqid); 312 p9pdu_readf(pdu, proto_version, "w", nwqid);
310 if (!errcode) { 313 if (!errcode) {
311 *wqids = 314 *wqids =
312 kmalloc(*nwqid * 315 kmalloc(*nwqid *
@@ -321,7 +324,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
321 324
322 for (i = 0; i < *nwqid; i++) { 325 for (i = 0; i < *nwqid; i++) {
323 errcode = 326 errcode =
324 p9pdu_readf(pdu, optional, 327 p9pdu_readf(pdu,
328 proto_version,
325 "Q", 329 "Q",
326 &(*wqids)[i]); 330 &(*wqids)[i]);
327 if (errcode) 331 if (errcode)
@@ -336,7 +340,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
336 } 340 }
337 break; 341 break;
338 case '?': 342 case '?':
339 if (!optional) 343 if (proto_version != p9_proto_2000u)
340 return 0; 344 return 0;
341 break; 345 break;
342 default: 346 default:
@@ -352,7 +356,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
352} 356}
353 357
354int 358int
355p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) 359p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
360 va_list ap)
356{ 361{
357 const char *ptr; 362 const char *ptr;
358 int errcode = 0; 363 int errcode = 0;
@@ -389,7 +394,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
389 if (sptr) 394 if (sptr)
390 len = MIN(strlen(sptr), USHORT_MAX); 395 len = MIN(strlen(sptr), USHORT_MAX);
391 396
392 errcode = p9pdu_writef(pdu, optional, "w", len); 397 errcode = p9pdu_writef(pdu, proto_version,
398 "w", len);
393 if (!errcode && pdu_write(pdu, sptr, len)) 399 if (!errcode && pdu_write(pdu, sptr, len))
394 errcode = -EFAULT; 400 errcode = -EFAULT;
395 } 401 }
@@ -398,7 +404,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
398 const struct p9_qid *qid = 404 const struct p9_qid *qid =
399 va_arg(ap, const struct p9_qid *); 405 va_arg(ap, const struct p9_qid *);
400 errcode = 406 errcode =
401 p9pdu_writef(pdu, optional, "bdq", 407 p9pdu_writef(pdu, proto_version, "bdq",
402 qid->type, qid->version, 408 qid->type, qid->version,
403 qid->path); 409 qid->path);
404 } break; 410 } break;
@@ -406,7 +412,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
406 const struct p9_wstat *stbuf = 412 const struct p9_wstat *stbuf =
407 va_arg(ap, const struct p9_wstat *); 413 va_arg(ap, const struct p9_wstat *);
408 errcode = 414 errcode =
409 p9pdu_writef(pdu, optional, 415 p9pdu_writef(pdu, proto_version,
410 "wwdQdddqssss?sddd", 416 "wwdQdddqssss?sddd",
411 stbuf->size, stbuf->type, 417 stbuf->size, stbuf->type,
412 stbuf->dev, &stbuf->qid, 418 stbuf->dev, &stbuf->qid,
@@ -421,8 +427,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
421 int32_t count = va_arg(ap, int32_t); 427 int32_t count = va_arg(ap, int32_t);
422 const void *data = va_arg(ap, const void *); 428 const void *data = va_arg(ap, const void *);
423 429
424 errcode = 430 errcode = p9pdu_writef(pdu, proto_version, "d",
425 p9pdu_writef(pdu, optional, "d", count); 431 count);
426 if (!errcode && pdu_write(pdu, data, count)) 432 if (!errcode && pdu_write(pdu, data, count))
427 errcode = -EFAULT; 433 errcode = -EFAULT;
428 } 434 }
@@ -431,8 +437,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
431 int32_t count = va_arg(ap, int32_t); 437 int32_t count = va_arg(ap, int32_t);
432 const char __user *udata = 438 const char __user *udata =
433 va_arg(ap, const void __user *); 439 va_arg(ap, const void __user *);
434 errcode = 440 errcode = p9pdu_writef(pdu, proto_version, "d",
435 p9pdu_writef(pdu, optional, "d", count); 441 count);
436 if (!errcode && pdu_write_u(pdu, udata, count)) 442 if (!errcode && pdu_write_u(pdu, udata, count))
437 errcode = -EFAULT; 443 errcode = -EFAULT;
438 } 444 }
@@ -441,14 +447,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
441 int16_t nwname = va_arg(ap, int); 447 int16_t nwname = va_arg(ap, int);
442 const char **wnames = va_arg(ap, const char **); 448 const char **wnames = va_arg(ap, const char **);
443 449
444 errcode = 450 errcode = p9pdu_writef(pdu, proto_version, "w",
445 p9pdu_writef(pdu, optional, "w", nwname); 451 nwname);
446 if (!errcode) { 452 if (!errcode) {
447 int i; 453 int i;
448 454
449 for (i = 0; i < nwname; i++) { 455 for (i = 0; i < nwname; i++) {
450 errcode = 456 errcode =
451 p9pdu_writef(pdu, optional, 457 p9pdu_writef(pdu,
458 proto_version,
452 "s", 459 "s",
453 wnames[i]); 460 wnames[i]);
454 if (errcode) 461 if (errcode)
@@ -462,14 +469,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
462 struct p9_qid *wqids = 469 struct p9_qid *wqids =
463 va_arg(ap, struct p9_qid *); 470 va_arg(ap, struct p9_qid *);
464 471
465 errcode = 472 errcode = p9pdu_writef(pdu, proto_version, "w",
466 p9pdu_writef(pdu, optional, "w", nwqid); 473 nwqid);
467 if (!errcode) { 474 if (!errcode) {
468 int i; 475 int i;
469 476
470 for (i = 0; i < nwqid; i++) { 477 for (i = 0; i < nwqid; i++) {
471 errcode = 478 errcode =
472 p9pdu_writef(pdu, optional, 479 p9pdu_writef(pdu,
480 proto_version,
473 "Q", 481 "Q",
474 &wqids[i]); 482 &wqids[i]);
475 if (errcode) 483 if (errcode)
@@ -479,7 +487,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
479 } 487 }
480 break; 488 break;
481 case '?': 489 case '?':
482 if (!optional) 490 if (proto_version != p9_proto_2000u)
483 return 0; 491 return 0;
484 break; 492 break;
485 default: 493 default:
@@ -494,32 +502,32 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
494 return errcode; 502 return errcode;
495} 503}
496 504
497int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...) 505int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
498{ 506{
499 va_list ap; 507 va_list ap;
500 int ret; 508 int ret;
501 509
502 va_start(ap, fmt); 510 va_start(ap, fmt);
503 ret = p9pdu_vreadf(pdu, optional, fmt, ap); 511 ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
504 va_end(ap); 512 va_end(ap);
505 513
506 return ret; 514 return ret;
507} 515}
508 516
509static int 517static int
510p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) 518p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
511{ 519{
512 va_list ap; 520 va_list ap;
513 int ret; 521 int ret;
514 522
515 va_start(ap, fmt); 523 va_start(ap, fmt);
516 ret = p9pdu_vwritef(pdu, optional, fmt, ap); 524 ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
517 va_end(ap); 525 va_end(ap);
518 526
519 return ret; 527 return ret;
520} 528}
521 529
522int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu) 530int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
523{ 531{
524 struct p9_fcall fake_pdu; 532 struct p9_fcall fake_pdu;
525 int ret; 533 int ret;
@@ -529,7 +537,7 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
529 fake_pdu.sdata = buf; 537 fake_pdu.sdata = buf;
530 fake_pdu.offset = 0; 538 fake_pdu.offset = 0;
531 539
532 ret = p9pdu_readf(&fake_pdu, dotu, "S", st); 540 ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
533 if (ret) { 541 if (ret) {
534 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); 542 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
535 p9pdu_dump(1, &fake_pdu); 543 p9pdu_dump(1, &fake_pdu);
diff --git a/net/9p/protocol.h b/net/9p/protocol.h
index ccde462e7ac5..2431c0f38d56 100644
--- a/net/9p/protocol.h
+++ b/net/9p/protocol.h
@@ -25,9 +25,9 @@
25 * 25 *
26 */ 26 */
27 27
28int 28int p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
29p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap); 29 va_list ap);
30int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...); 30int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
31int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type); 31int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type);
32int p9pdu_finalize(struct p9_fcall *pdu); 32int p9pdu_finalize(struct p9_fcall *pdu);
33void p9pdu_dump(int, struct p9_fcall *); 33void p9pdu_dump(int, struct p9_fcall *);
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index cb50f4ae5eef..0aaed4819379 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -49,8 +49,6 @@
49 49
50/* a single mutex to manage channel initialization and attachment */ 50/* a single mutex to manage channel initialization and attachment */
51static DEFINE_MUTEX(virtio_9p_lock); 51static DEFINE_MUTEX(virtio_9p_lock);
52/* global which tracks highest initialized channel */
53static int chan_index;
54 52
55/** 53/**
56 * struct virtio_chan - per-instance transport information 54 * struct virtio_chan - per-instance transport information
@@ -68,8 +66,7 @@ static int chan_index;
68 * 66 *
69 */ 67 */
70 68
71static struct virtio_chan { 69struct virtio_chan {
72 bool initialized;
73 bool inuse; 70 bool inuse;
74 71
75 spinlock_t lock; 72 spinlock_t lock;
@@ -80,7 +77,11 @@ static struct virtio_chan {
80 77
81 /* Scatterlist: can be too big for stack. */ 78 /* Scatterlist: can be too big for stack. */
82 struct scatterlist sg[VIRTQUEUE_NUM]; 79 struct scatterlist sg[VIRTQUEUE_NUM];
83} channels[MAX_9P_CHAN]; 80
81 struct list_head chan_list;
82};
83
84static struct list_head virtio_chan_list;
84 85
85/* How many bytes left in this page. */ 86/* How many bytes left in this page. */
86static unsigned int rest_of_page(void *data) 87static unsigned int rest_of_page(void *data)
@@ -217,9 +218,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
217 * p9_virtio_probe - probe for existence of 9P virtio channels 218 * p9_virtio_probe - probe for existence of 9P virtio channels
218 * @vdev: virtio device to probe 219 * @vdev: virtio device to probe
219 * 220 *
220 * This probes for existing virtio channels. At present only 221 * This probes for existing virtio channels.
221 * a single channel is in use, so in the future more work may need
222 * to be done here.
223 * 222 *
224 */ 223 */
225 224
@@ -227,16 +226,10 @@ static int p9_virtio_probe(struct virtio_device *vdev)
227{ 226{
228 int err; 227 int err;
229 struct virtio_chan *chan; 228 struct virtio_chan *chan;
230 int index;
231 229
232 mutex_lock(&virtio_9p_lock); 230 chan = kmalloc(sizeof(struct virtio_chan), GFP_KERNEL);
233 index = chan_index++; 231 if (!chan) {
234 chan = &channels[index]; 232 printk(KERN_ERR "9p: Failed to allocate virtio 9P channel\n");
235 mutex_unlock(&virtio_9p_lock);
236
237 if (chan_index > MAX_9P_CHAN) {
238 printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
239 BUG();
240 err = -ENOMEM; 233 err = -ENOMEM;
241 goto fail; 234 goto fail;
242 } 235 }
@@ -255,15 +248,15 @@ static int p9_virtio_probe(struct virtio_device *vdev)
255 sg_init_table(chan->sg, VIRTQUEUE_NUM); 248 sg_init_table(chan->sg, VIRTQUEUE_NUM);
256 249
257 chan->inuse = false; 250 chan->inuse = false;
258 chan->initialized = true; 251 mutex_lock(&virtio_9p_lock);
252 list_add_tail(&chan->chan_list, &virtio_chan_list);
253 mutex_unlock(&virtio_9p_lock);
259 return 0; 254 return 0;
260 255
261out_free_vq: 256out_free_vq:
262 vdev->config->del_vqs(vdev); 257 vdev->config->del_vqs(vdev);
258 kfree(chan);
263fail: 259fail:
264 mutex_lock(&virtio_9p_lock);
265 chan_index--;
266 mutex_unlock(&virtio_9p_lock);
267 return err; 260 return err;
268} 261}
269 262
@@ -280,35 +273,31 @@ fail:
280 * We use a simple reference count mechanism to ensure that only a single 273 * We use a simple reference count mechanism to ensure that only a single
281 * mount has a channel open at a time. 274 * mount has a channel open at a time.
282 * 275 *
283 * Bugs: doesn't allow identification of a specific channel
284 * to allocate, channels are allocated sequentially. This was
285 * a pragmatic decision to get things rolling, but ideally some
286 * way of identifying the channel to attach to would be nice
287 * if we are going to support multiple channels.
288 *
289 */ 276 */
290 277
291static int 278static int
292p9_virtio_create(struct p9_client *client, const char *devname, char *args) 279p9_virtio_create(struct p9_client *client, const char *devname, char *args)
293{ 280{
294 struct virtio_chan *chan = channels; 281 struct virtio_chan *chan;
295 int index = 0; 282 int ret = -ENOENT;
283 int found = 0;
296 284
297 mutex_lock(&virtio_9p_lock); 285 mutex_lock(&virtio_9p_lock);
298 while (index < MAX_9P_CHAN) { 286 list_for_each_entry(chan, &virtio_chan_list, chan_list) {
299 if (chan->initialized && !chan->inuse) { 287 if (!strcmp(devname, dev_name(&chan->vdev->dev))) {
300 chan->inuse = true; 288 if (!chan->inuse) {
301 break; 289 chan->inuse = true;
302 } else { 290 found = 1;
303 index++; 291 break;
304 chan = &channels[index]; 292 }
293 ret = -EBUSY;
305 } 294 }
306 } 295 }
307 mutex_unlock(&virtio_9p_lock); 296 mutex_unlock(&virtio_9p_lock);
308 297
309 if (index >= MAX_9P_CHAN) { 298 if (!found) {
310 printk(KERN_ERR "9p: no channels available\n"); 299 printk(KERN_ERR "9p: no channels available\n");
311 return -ENODEV; 300 return ret;
312 } 301 }
313 302
314 client->trans = (void *)chan; 303 client->trans = (void *)chan;
@@ -329,11 +318,13 @@ static void p9_virtio_remove(struct virtio_device *vdev)
329 struct virtio_chan *chan = vdev->priv; 318 struct virtio_chan *chan = vdev->priv;
330 319
331 BUG_ON(chan->inuse); 320 BUG_ON(chan->inuse);
321 vdev->config->del_vqs(vdev);
322
323 mutex_lock(&virtio_9p_lock);
324 list_del(&chan->chan_list);
325 mutex_unlock(&virtio_9p_lock);
326 kfree(chan);
332 327
333 if (chan->initialized) {
334 vdev->config->del_vqs(vdev);
335 chan->initialized = false;
336 }
337} 328}
338 329
339static struct virtio_device_id id_table[] = { 330static struct virtio_device_id id_table[] = {
@@ -364,10 +355,7 @@ static struct p9_trans_module p9_virtio_trans = {
364/* The standard init function */ 355/* The standard init function */
365static int __init p9_virtio_init(void) 356static int __init p9_virtio_init(void)
366{ 357{
367 int count; 358 INIT_LIST_HEAD(&virtio_chan_list);
368
369 for (count = 0; count < MAX_9P_CHAN; count++)
370 channels[count].initialized = false;
371 359
372 v9fs_register_trans(&p9_virtio_trans); 360 v9fs_register_trans(&p9_virtio_trans);
373 return register_virtio_driver(&p9_virtio_drv); 361 return register_virtio_driver(&p9_virtio_drv);