aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-10-20 12:39:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-20 12:39:47 -0400
commit45e4a24f7b6b23810142112b5850fe75696a1155 (patch)
treec6a46c3d19a0406b477240ecae7a41886c9ad7d0
parent52c6738b7f46255217942062dfa60daa7cf72510 (diff)
parent7eb923b80c8ce16697129fb2dcdfaeabf83f0dbc (diff)
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 ...
-rw-r--r--fs/9p/v9fs.c4
-rw-r--r--fs/9p/v9fs_vfs.h6
-rw-r--r--fs/9p/vfs_addr.c5
-rw-r--r--fs/9p/vfs_dir.c60
-rw-r--r--fs/9p/vfs_file.c93
-rw-r--r--fs/9p/vfs_inode.c39
-rw-r--r--fs/9p/vfs_super.c6
-rw-r--r--include/net/9p/9p.h119
-rw-r--r--include/net/9p/client.h124
-rw-r--r--include/net/9p/transport.h55
-rw-r--r--net/9p/Makefile3
-rw-r--r--net/9p/client.c1467
-rw-r--r--net/9p/conv.c1054
-rw-r--r--net/9p/fcprint.c366
-rw-r--r--net/9p/mod.c1
-rw-r--r--net/9p/protocol.c558
-rw-r--r--net/9p/protocol.h34
-rw-r--r--net/9p/trans_fd.c1431
-rw-r--r--net/9p/trans_virtio.c246
-rw-r--r--net/9p/util.c4
20 files changed, 2224 insertions, 3451 deletions
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index c061c3f18e7c..24eb01087b6d 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -30,8 +30,8 @@
30#include <linux/parser.h> 30#include <linux/parser.h>
31#include <linux/idr.h> 31#include <linux/idr.h>
32#include <net/9p/9p.h> 32#include <net/9p/9p.h>
33#include <net/9p/transport.h>
34#include <net/9p/client.h> 33#include <net/9p/client.h>
34#include <net/9p/transport.h>
35#include "v9fs.h" 35#include "v9fs.h"
36#include "v9fs_vfs.h" 36#include "v9fs_vfs.h"
37 37
@@ -234,7 +234,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
234 if (!v9ses->clnt->dotu) 234 if (!v9ses->clnt->dotu)
235 v9ses->flags &= ~V9FS_EXTENDED; 235 v9ses->flags &= ~V9FS_EXTENDED;
236 236
237 v9ses->maxdata = v9ses->clnt->msize; 237 v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
238 238
239 /* for legacy mode, fall back to V9FS_ACCESS_ANY */ 239 /* for legacy mode, fall back to V9FS_ACCESS_ANY */
240 if (!v9fs_extended(v9ses) && 240 if (!v9fs_extended(v9ses) &&
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 57997fa14e69..c295ba786edd 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -46,9 +46,11 @@ extern struct dentry_operations v9fs_cached_dentry_operations;
46 46
47struct inode *v9fs_get_inode(struct super_block *sb, int mode); 47struct inode *v9fs_get_inode(struct super_block *sb, int mode);
48ino_t v9fs_qid2ino(struct p9_qid *qid); 48ino_t v9fs_qid2ino(struct p9_qid *qid);
49void v9fs_stat2inode(struct p9_stat *, struct inode *, struct super_block *); 49void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
50int v9fs_dir_release(struct inode *inode, struct file *filp); 50int v9fs_dir_release(struct inode *inode, struct file *filp);
51int v9fs_file_open(struct inode *inode, struct file *file); 51int v9fs_file_open(struct inode *inode, struct file *file);
52void v9fs_inode2stat(struct inode *inode, struct p9_stat *stat); 52void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
53void v9fs_dentry_release(struct dentry *); 53void v9fs_dentry_release(struct dentry *);
54int v9fs_uflags2omode(int uflags, int extended); 54int v9fs_uflags2omode(int uflags, int extended);
55
56ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 97d3aed57983..6fcb1e7095cf 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -38,7 +38,6 @@
38 38
39#include "v9fs.h" 39#include "v9fs.h"
40#include "v9fs_vfs.h" 40#include "v9fs_vfs.h"
41#include "fid.h"
42 41
43/** 42/**
44 * v9fs_vfs_readpage - read an entire page in from 9P 43 * v9fs_vfs_readpage - read an entire page in from 9P
@@ -53,14 +52,12 @@ static int v9fs_vfs_readpage(struct file *filp, struct page *page)
53 int retval; 52 int retval;
54 loff_t offset; 53 loff_t offset;
55 char *buffer; 54 char *buffer;
56 struct p9_fid *fid;
57 55
58 P9_DPRINTK(P9_DEBUG_VFS, "\n"); 56 P9_DPRINTK(P9_DEBUG_VFS, "\n");
59 fid = filp->private_data;
60 buffer = kmap(page); 57 buffer = kmap(page);
61 offset = page_offset(page); 58 offset = page_offset(page);
62 59
63 retval = p9_client_readn(fid, buffer, offset, PAGE_CACHE_SIZE); 60 retval = v9fs_file_readn(filp, buffer, NULL, offset, PAGE_CACHE_SIZE);
64 if (retval < 0) 61 if (retval < 0)
65 goto done; 62 goto done;
66 63
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index e298fe194093..873cd31baa47 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -45,7 +45,7 @@
45 * 45 *
46 */ 46 */
47 47
48static inline int dt_type(struct p9_stat *mistat) 48static inline int dt_type(struct p9_wstat *mistat)
49{ 49{
50 unsigned long perm = mistat->mode; 50 unsigned long perm = mistat->mode;
51 int rettype = DT_REG; 51 int rettype = DT_REG;
@@ -69,32 +69,58 @@ static inline int dt_type(struct p9_stat *mistat)
69static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) 69static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
70{ 70{
71 int over; 71 int over;
72 struct p9_wstat st;
73 int err;
72 struct p9_fid *fid; 74 struct p9_fid *fid;
73 struct v9fs_session_info *v9ses; 75 int buflen;
74 struct inode *inode; 76 char *statbuf;
75 struct p9_stat *st; 77 int n, i = 0;
76 78
77 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); 79 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
78 inode = filp->f_path.dentry->d_inode;
79 v9ses = v9fs_inode2v9ses(inode);
80 fid = filp->private_data; 80 fid = filp->private_data;
81 while ((st = p9_client_dirread(fid, filp->f_pos)) != NULL) {
82 if (IS_ERR(st))
83 return PTR_ERR(st);
84 81
85 over = filldir(dirent, st->name.str, st->name.len, filp->f_pos, 82 buflen = fid->clnt->msize - P9_IOHDRSZ;
86 v9fs_qid2ino(&st->qid), dt_type(st)); 83 statbuf = kmalloc(buflen, GFP_KERNEL);
84 if (!statbuf)
85 return -ENOMEM;
87 86
88 if (over) 87 while (1) {
88 err = v9fs_file_readn(filp, statbuf, NULL, buflen,
89 fid->rdir_fpos);
90 if (err <= 0)
89 break; 91 break;
90 92
91 filp->f_pos += st->size; 93 n = err;
92 kfree(st); 94 while (i < n) {
93 st = NULL; 95 err = p9stat_read(statbuf + i, buflen-i, &st,
96 fid->clnt->dotu);
97 if (err) {
98 P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
99 err = -EIO;
100 p9stat_free(&st);
101 goto free_and_exit;
102 }
103
104 i += st.size+2;
105 fid->rdir_fpos += st.size+2;
106
107 over = filldir(dirent, st.name, strlen(st.name),
108 filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st));
109
110 filp->f_pos += st.size+2;
111
112 p9stat_free(&st);
113
114 if (over) {
115 err = 0;
116 goto free_and_exit;
117 }
118 }
94 } 119 }
95 120
96 kfree(st); 121free_and_exit:
97 return 0; 122 kfree(statbuf);
123 return err;
98} 124}
99 125
100 126
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 52944d2249a4..041c52692284 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -120,23 +120,72 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
120} 120}
121 121
122/** 122/**
123 * v9fs_file_read - read from a file 123 * v9fs_file_readn - read from a file
124 * @filp: file pointer to read 124 * @filp: file pointer to read
125 * @data: data buffer to read data into 125 * @data: data buffer to read data into
126 * @udata: user data buffer to read data into
126 * @count: size of buffer 127 * @count: size of buffer
127 * @offset: offset at which to read data 128 * @offset: offset at which to read data
128 * 129 *
129 */ 130 */
131
132ssize_t
133v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
134 u64 offset)
135{
136 int n, total;
137 struct p9_fid *fid = filp->private_data;
138
139 P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
140 (long long unsigned) offset, count);
141
142 n = 0;
143 total = 0;
144 do {
145 n = p9_client_read(fid, data, udata, offset, count);
146 if (n <= 0)
147 break;
148
149 if (data)
150 data += n;
151 if (udata)
152 udata += n;
153
154 offset += n;
155 count -= n;
156 total += n;
157 } while (count > 0 && n == (fid->clnt->msize - P9_IOHDRSZ));
158
159 if (n < 0)
160 total = n;
161
162 return total;
163}
164
165/**
166 * v9fs_file_read - read from a file
167 * @filp: file pointer to read
168 * @udata: user data buffer to read data into
169 * @count: size of buffer
170 * @offset: offset at which to read data
171 *
172 */
173
130static ssize_t 174static ssize_t
131v9fs_file_read(struct file *filp, char __user * data, size_t count, 175v9fs_file_read(struct file *filp, char __user *udata, size_t count,
132 loff_t * offset) 176 loff_t * offset)
133{ 177{
134 int ret; 178 int ret;
135 struct p9_fid *fid; 179 struct p9_fid *fid;
136 180
137 P9_DPRINTK(P9_DEBUG_VFS, "\n"); 181 P9_DPRINTK(P9_DEBUG_VFS, "count %d offset %lld\n", count, *offset);
138 fid = filp->private_data; 182 fid = filp->private_data;
139 ret = p9_client_uread(fid, data, *offset, count); 183
184 if (count > (fid->clnt->msize - P9_IOHDRSZ))
185 ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
186 else
187 ret = p9_client_read(fid, NULL, udata, *offset, count);
188
140 if (ret > 0) 189 if (ret > 0)
141 *offset += ret; 190 *offset += ret;
142 191
@@ -156,19 +205,38 @@ static ssize_t
156v9fs_file_write(struct file *filp, const char __user * data, 205v9fs_file_write(struct file *filp, const char __user * data,
157 size_t count, loff_t * offset) 206 size_t count, loff_t * offset)
158{ 207{
159 int ret; 208 int n, rsize, total = 0;
160 struct p9_fid *fid; 209 struct p9_fid *fid;
210 struct p9_client *clnt;
161 struct inode *inode = filp->f_path.dentry->d_inode; 211 struct inode *inode = filp->f_path.dentry->d_inode;
212 int origin = *offset;
162 213
163 P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, 214 P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
164 (int)count, (int)*offset); 215 (int)count, (int)*offset);
165 216
166 fid = filp->private_data; 217 fid = filp->private_data;
167 ret = p9_client_uwrite(fid, data, *offset, count); 218 clnt = fid->clnt;
168 if (ret > 0) { 219
169 invalidate_inode_pages2_range(inode->i_mapping, *offset, 220 rsize = fid->iounit;
170 *offset+ret); 221 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
171 *offset += ret; 222 rsize = clnt->msize - P9_IOHDRSZ;
223
224 do {
225 if (count < rsize)
226 rsize = count;
227
228 n = p9_client_write(fid, NULL, data+total, *offset+total,
229 rsize);
230 if (n <= 0)
231 break;
232 count -= n;
233 total += n;
234 } while (count > 0);
235
236 if (total > 0) {
237 invalidate_inode_pages2_range(inode->i_mapping, origin,
238 origin+total);
239 *offset += total;
172 } 240 }
173 241
174 if (*offset > inode->i_size) { 242 if (*offset > inode->i_size) {
@@ -176,7 +244,10 @@ v9fs_file_write(struct file *filp, const char __user * data,
176 inode->i_blocks = (inode->i_size + 512 - 1) >> 9; 244 inode->i_blocks = (inode->i_size + 512 - 1) >> 9;
177 } 245 }
178 246
179 return ret; 247 if (n < 0)
248 return n;
249
250 return total;
180} 251}
181 252
182static const struct file_operations v9fs_cached_file_operations = { 253static const struct file_operations v9fs_cached_file_operations = {
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index e83aa5ebe861..8314d3f43b71 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -334,7 +334,7 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
334{ 334{
335 int err, umode; 335 int err, umode;
336 struct inode *ret; 336 struct inode *ret;
337 struct p9_stat *st; 337 struct p9_wstat *st;
338 338
339 ret = NULL; 339 ret = NULL;
340 st = p9_client_stat(fid); 340 st = p9_client_stat(fid);
@@ -417,6 +417,8 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
417 struct p9_fid *dfid, *ofid, *fid; 417 struct p9_fid *dfid, *ofid, *fid;
418 struct inode *inode; 418 struct inode *inode;
419 419
420 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
421
420 err = 0; 422 err = 0;
421 ofid = NULL; 423 ofid = NULL;
422 fid = NULL; 424 fid = NULL;
@@ -424,6 +426,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
424 dfid = v9fs_fid_clone(dentry->d_parent); 426 dfid = v9fs_fid_clone(dentry->d_parent);
425 if (IS_ERR(dfid)) { 427 if (IS_ERR(dfid)) {
426 err = PTR_ERR(dfid); 428 err = PTR_ERR(dfid);
429 P9_DPRINTK(P9_DEBUG_VFS, "fid clone failed %d\n", err);
427 dfid = NULL; 430 dfid = NULL;
428 goto error; 431 goto error;
429 } 432 }
@@ -432,18 +435,22 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
432 ofid = p9_client_walk(dfid, 0, NULL, 1); 435 ofid = p9_client_walk(dfid, 0, NULL, 1);
433 if (IS_ERR(ofid)) { 436 if (IS_ERR(ofid)) {
434 err = PTR_ERR(ofid); 437 err = PTR_ERR(ofid);
438 P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
435 ofid = NULL; 439 ofid = NULL;
436 goto error; 440 goto error;
437 } 441 }
438 442
439 err = p9_client_fcreate(ofid, name, perm, mode, extension); 443 err = p9_client_fcreate(ofid, name, perm, mode, extension);
440 if (err < 0) 444 if (err < 0) {
445 P9_DPRINTK(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err);
441 goto error; 446 goto error;
447 }
442 448
443 /* now walk from the parent so we can get unopened fid */ 449 /* now walk from the parent so we can get unopened fid */
444 fid = p9_client_walk(dfid, 1, &name, 0); 450 fid = p9_client_walk(dfid, 1, &name, 0);
445 if (IS_ERR(fid)) { 451 if (IS_ERR(fid)) {
446 err = PTR_ERR(fid); 452 err = PTR_ERR(fid);
453 P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
447 fid = NULL; 454 fid = NULL;
448 goto error; 455 goto error;
449 } else 456 } else
@@ -453,6 +460,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
453 inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); 460 inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
454 if (IS_ERR(inode)) { 461 if (IS_ERR(inode)) {
455 err = PTR_ERR(inode); 462 err = PTR_ERR(inode);
463 P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
456 goto error; 464 goto error;
457 } 465 }
458 466
@@ -734,7 +742,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
734 int err; 742 int err;
735 struct v9fs_session_info *v9ses; 743 struct v9fs_session_info *v9ses;
736 struct p9_fid *fid; 744 struct p9_fid *fid;
737 struct p9_stat *st; 745 struct p9_wstat *st;
738 746
739 P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); 747 P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
740 err = -EPERM; 748 err = -EPERM;
@@ -815,10 +823,9 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
815 */ 823 */
816 824
817void 825void
818v9fs_stat2inode(struct p9_stat *stat, struct inode *inode, 826v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
819 struct super_block *sb) 827 struct super_block *sb)
820{ 828{
821 int n;
822 char ext[32]; 829 char ext[32];
823 struct v9fs_session_info *v9ses = sb->s_fs_info; 830 struct v9fs_session_info *v9ses = sb->s_fs_info;
824 831
@@ -842,11 +849,7 @@ v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
842 int major = -1; 849 int major = -1;
843 int minor = -1; 850 int minor = -1;
844 851
845 n = stat->extension.len; 852 strncpy(ext, stat->extension, sizeof(ext));
846 if (n > sizeof(ext)-1)
847 n = sizeof(ext)-1;
848 memmove(ext, stat->extension.str, n);
849 ext[n] = 0;
850 sscanf(ext, "%c %u %u", &type, &major, &minor); 853 sscanf(ext, "%c %u %u", &type, &major, &minor);
851 switch (type) { 854 switch (type) {
852 case 'c': 855 case 'c':
@@ -857,10 +860,11 @@ v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
857 break; 860 break;
858 default: 861 default:
859 P9_DPRINTK(P9_DEBUG_ERROR, 862 P9_DPRINTK(P9_DEBUG_ERROR,
860 "Unknown special type %c (%.*s)\n", type, 863 "Unknown special type %c %s\n", type,
861 stat->extension.len, stat->extension.str); 864 stat->extension);
862 }; 865 };
863 inode->i_rdev = MKDEV(major, minor); 866 inode->i_rdev = MKDEV(major, minor);
867 init_special_inode(inode, inode->i_mode, inode->i_rdev);
864 } else 868 } else
865 inode->i_rdev = 0; 869 inode->i_rdev = 0;
866 870
@@ -904,7 +908,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
904 908
905 struct v9fs_session_info *v9ses; 909 struct v9fs_session_info *v9ses;
906 struct p9_fid *fid; 910 struct p9_fid *fid;
907 struct p9_stat *st; 911 struct p9_wstat *st;
908 912
909 P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); 913 P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
910 retval = -EPERM; 914 retval = -EPERM;
@@ -926,15 +930,10 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
926 } 930 }
927 931
928 /* copy extension buffer into buffer */ 932 /* copy extension buffer into buffer */
929 if (st->extension.len < buflen) 933 strncpy(buffer, st->extension, buflen);
930 buflen = st->extension.len + 1;
931
932 memmove(buffer, st->extension.str, buflen - 1);
933 buffer[buflen-1] = 0;
934 934
935 P9_DPRINTK(P9_DEBUG_VFS, 935 P9_DPRINTK(P9_DEBUG_VFS,
936 "%s -> %.*s (%s)\n", dentry->d_name.name, st->extension.len, 936 "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer);
937 st->extension.str, buffer);
938 937
939 retval = buflen; 938 retval = buflen;
940 939
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index bf59c3960494..d6cb1a0ca724 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -111,7 +111,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
111 struct inode *inode = NULL; 111 struct inode *inode = NULL;
112 struct dentry *root = NULL; 112 struct dentry *root = NULL;
113 struct v9fs_session_info *v9ses = NULL; 113 struct v9fs_session_info *v9ses = NULL;
114 struct p9_stat *st = NULL; 114 struct p9_wstat *st = NULL;
115 int mode = S_IRWXUGO | S_ISVTX; 115 int mode = S_IRWXUGO | S_ISVTX;
116 uid_t uid = current->fsuid; 116 uid_t uid = current->fsuid;
117 gid_t gid = current->fsgid; 117 gid_t gid = current->fsgid;
@@ -161,10 +161,14 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
161 161
162 sb->s_root = root; 162 sb->s_root = root;
163 root->d_inode->i_ino = v9fs_qid2ino(&st->qid); 163 root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
164
164 v9fs_stat2inode(st, root->d_inode, sb); 165 v9fs_stat2inode(st, root->d_inode, sb);
166
165 v9fs_fid_add(root, fid); 167 v9fs_fid_add(root, fid);
168 p9stat_free(st);
166 kfree(st); 169 kfree(st);
167 170
171P9_DPRINTK(P9_DEBUG_VFS, " return simple set mount\n");
168 return simple_set_mnt(mnt, sb); 172 return simple_set_mnt(mnt, sb);
169 173
170release_sb: 174release_sb:
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index fb163e2e0de6..d2c60c73619d 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -27,8 +27,6 @@
27#ifndef NET_9P_H 27#ifndef NET_9P_H
28#define NET_9P_H 28#define NET_9P_H
29 29
30#ifdef CONFIG_NET_9P_DEBUG
31
32/** 30/**
33 * enum p9_debug_flags - bits for mount time debug parameter 31 * enum p9_debug_flags - bits for mount time debug parameter
34 * @P9_DEBUG_ERROR: more verbose error messages including original error string 32 * @P9_DEBUG_ERROR: more verbose error messages including original error string
@@ -39,6 +37,7 @@
39 * @P9_DEBUG_TRANS: transport tracing 37 * @P9_DEBUG_TRANS: transport tracing
40 * @P9_DEBUG_SLABS: memory management tracing 38 * @P9_DEBUG_SLABS: memory management tracing
41 * @P9_DEBUG_FCALL: verbose dump of protocol messages 39 * @P9_DEBUG_FCALL: verbose dump of protocol messages
40 * @P9_DEBUG_FID: fid allocation/deallocation tracking
42 * 41 *
43 * These flags are passed at mount time to turn on various levels of 42 * These flags are passed at mount time to turn on various levels of
44 * verbosity and tracing which will be output to the system logs. 43 * verbosity and tracing which will be output to the system logs.
@@ -53,24 +52,27 @@ enum p9_debug_flags {
53 P9_DEBUG_TRANS = (1<<6), 52 P9_DEBUG_TRANS = (1<<6),
54 P9_DEBUG_SLABS = (1<<7), 53 P9_DEBUG_SLABS = (1<<7),
55 P9_DEBUG_FCALL = (1<<8), 54 P9_DEBUG_FCALL = (1<<8),
55 P9_DEBUG_FID = (1<<9),
56 P9_DEBUG_PKT = (1<<10),
56}; 57};
57 58
58extern unsigned int p9_debug_level; 59extern unsigned int p9_debug_level;
59 60
61#ifdef CONFIG_NET_9P_DEBUG
60#define P9_DPRINTK(level, format, arg...) \ 62#define P9_DPRINTK(level, format, arg...) \
61do { \ 63do { \
62 if ((p9_debug_level & level) == level) \ 64 if ((p9_debug_level & level) == level) {\
63 printk(KERN_NOTICE "-- %s (%d): " \ 65 if (level == P9_DEBUG_9P) \
64 format , __func__, task_pid_nr(current) , ## arg); \ 66 printk(KERN_NOTICE "(%8.8d) " \
67 format , task_pid_nr(current) , ## arg); \
68 else \
69 printk(KERN_NOTICE "-- %s (%d): " \
70 format , __func__, task_pid_nr(current) , ## arg); \
71 } \
65} while (0) 72} while (0)
66 73
67#define PRINT_FCALL_ERROR(s, fcall) P9_DPRINTK(P9_DEBUG_ERROR, \
68 "%s: %.*s\n", s, fcall?fcall->params.rerror.error.len:0, \
69 fcall?fcall->params.rerror.error.str:"");
70
71#else 74#else
72#define P9_DPRINTK(level, format, arg...) do { } while (0) 75#define P9_DPRINTK(level, format, arg...) do { } while (0)
73#define PRINT_FCALL_ERROR(s, fcall) do { } while (0)
74#endif 76#endif
75 77
76#define P9_EPRINTK(level, format, arg...) \ 78#define P9_EPRINTK(level, format, arg...) \
@@ -325,33 +327,6 @@ struct p9_qid {
325 * See Also: http://plan9.bell-labs.com/magic/man2html/2/stat 327 * See Also: http://plan9.bell-labs.com/magic/man2html/2/stat
326 */ 328 */
327 329
328struct p9_stat {
329 u16 size;
330 u16 type;
331 u32 dev;
332 struct p9_qid qid;
333 u32 mode;
334 u32 atime;
335 u32 mtime;
336 u64 length;
337 struct p9_str name;
338 struct p9_str uid;
339 struct p9_str gid;
340 struct p9_str muid;
341 struct p9_str extension; /* 9p2000.u extensions */
342 u32 n_uid; /* 9p2000.u extensions */
343 u32 n_gid; /* 9p2000.u extensions */
344 u32 n_muid; /* 9p2000.u extensions */
345};
346
347/*
348 * file metadata (stat) structure used to create Twstat message
349 * The is identical to &p9_stat, but the strings don't point to
350 * the same memory block and should be freed separately
351 *
352 * See Also: http://plan9.bell-labs.com/magic/man2html/2/stat
353 */
354
355struct p9_wstat { 330struct p9_wstat {
356 u16 size; 331 u16 size;
357 u16 type; 332 u16 type;
@@ -493,12 +468,12 @@ struct p9_tstat {
493}; 468};
494 469
495struct p9_rstat { 470struct p9_rstat {
496 struct p9_stat stat; 471 struct p9_wstat stat;
497}; 472};
498 473
499struct p9_twstat { 474struct p9_twstat {
500 u32 fid; 475 u32 fid;
501 struct p9_stat stat; 476 struct p9_wstat stat;
502}; 477};
503 478
504struct p9_rwstat { 479struct p9_rwstat {
@@ -509,8 +484,9 @@ struct p9_rwstat {
509 * @size: prefixed length of the structure 484 * @size: prefixed length of the structure
510 * @id: protocol operating identifier of type &p9_msg_t 485 * @id: protocol operating identifier of type &p9_msg_t
511 * @tag: transaction id of the request 486 * @tag: transaction id of the request
487 * @offset: used by marshalling routines to track currentposition in buffer
488 * @capacity: used by marshalling routines to track total capacity
512 * @sdata: payload 489 * @sdata: payload
513 * @params: per-operation parameters
514 * 490 *
515 * &p9_fcall represents the structure for all 9P RPC 491 * &p9_fcall represents the structure for all 9P RPC
516 * transactions. Requests are packaged into fcalls, and reponses 492 * transactions. Requests are packaged into fcalls, and reponses
@@ -523,68 +499,15 @@ struct p9_fcall {
523 u32 size; 499 u32 size;
524 u8 id; 500 u8 id;
525 u16 tag; 501 u16 tag;
526 void *sdata; 502
527 503 size_t offset;
528 union { 504 size_t capacity;
529 struct p9_tversion tversion; 505
530 struct p9_rversion rversion; 506 uint8_t *sdata;
531 struct p9_tauth tauth;
532 struct p9_rauth rauth;
533 struct p9_rerror rerror;
534 struct p9_tflush tflush;
535 struct p9_rflush rflush;
536 struct p9_tattach tattach;
537 struct p9_rattach rattach;
538 struct p9_twalk twalk;
539 struct p9_rwalk rwalk;
540 struct p9_topen topen;
541 struct p9_ropen ropen;
542 struct p9_tcreate tcreate;
543 struct p9_rcreate rcreate;
544 struct p9_tread tread;
545 struct p9_rread rread;
546 struct p9_twrite twrite;
547 struct p9_rwrite rwrite;
548 struct p9_tclunk tclunk;
549 struct p9_rclunk rclunk;
550 struct p9_tremove tremove;
551 struct p9_rremove rremove;
552 struct p9_tstat tstat;
553 struct p9_rstat rstat;
554 struct p9_twstat twstat;
555 struct p9_rwstat rwstat;
556 } params;
557}; 507};
558 508
559struct p9_idpool; 509struct p9_idpool;
560 510
561int p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat,
562 int dotu);
563int p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *fc, int dotu);
564void p9_set_tag(struct p9_fcall *fc, u16 tag);
565struct p9_fcall *p9_create_tversion(u32 msize, char *version);
566struct p9_fcall *p9_create_tattach(u32 fid, u32 afid, char *uname,
567 char *aname, u32 n_uname, int dotu);
568struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname,
569 u32 n_uname, int dotu);
570struct p9_fcall *p9_create_tflush(u16 oldtag);
571struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
572 char **wnames);
573struct p9_fcall *p9_create_topen(u32 fid, u8 mode);
574struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
575 char *extension, int dotu);
576struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count);
577struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count,
578 const char *data);
579struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count,
580 const char __user *data);
581struct p9_fcall *p9_create_tclunk(u32 fid);
582struct p9_fcall *p9_create_tremove(u32 fid);
583struct p9_fcall *p9_create_tstat(u32 fid);
584struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat,
585 int dotu);
586
587int p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int dotu);
588int p9_errstr2errno(char *errstr, int len); 511int p9_errstr2errno(char *errstr, int len);
589 512
590struct p9_idpool *p9_idpool_create(void); 513struct p9_idpool *p9_idpool_create(void);
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index c936dd14de41..1f17f3d93727 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -26,6 +26,87 @@
26#ifndef NET_9P_CLIENT_H 26#ifndef NET_9P_CLIENT_H
27#define NET_9P_CLIENT_H 27#define NET_9P_CLIENT_H
28 28
29/* Number of requests per row */
30#define P9_ROW_MAXTAG 255
31
32/**
33 * enum p9_trans_status - different states of underlying transports
34 * @Connected: transport is connected and healthy
35 * @Disconnected: transport has been disconnected
36 * @Hung: transport is connected by wedged
37 *
38 * This enumeration details the various states a transport
39 * instatiation can be in.
40 */
41
42enum p9_trans_status {
43 Connected,
44 Disconnected,
45 Hung,
46};
47
48/**
49 * enum p9_req_status_t - virtio request status
50 * @REQ_STATUS_IDLE: request slot unused
51 * @REQ_STATUS_ALLOC: request has been allocated but not sent
52 * @REQ_STATUS_UNSENT: request waiting to be sent
53 * @REQ_STATUS_SENT: request sent to server
54 * @REQ_STATUS_FLSH: a flush has been sent for this request
55 * @REQ_STATUS_RCVD: response received from server
56 * @REQ_STATUS_FLSHD: request has been flushed
57 * @REQ_STATUS_ERROR: request encountered an error on the client side
58 *
59 * The @REQ_STATUS_IDLE state is used to mark a request slot as unused
60 * but use is actually tracked by the idpool structure which handles tag
61 * id allocation.
62 *
63 */
64
65enum p9_req_status_t {
66 REQ_STATUS_IDLE,
67 REQ_STATUS_ALLOC,
68 REQ_STATUS_UNSENT,
69 REQ_STATUS_SENT,
70 REQ_STATUS_FLSH,
71 REQ_STATUS_RCVD,
72 REQ_STATUS_FLSHD,
73 REQ_STATUS_ERROR,
74};
75
76/**
77 * struct p9_req_t - request slots
78 * @status: status of this request slot
79 * @t_err: transport error
80 * @flush_tag: tag of request being flushed (for flush requests)
81 * @wq: wait_queue for the client to block on for this request
82 * @tc: the request fcall structure
83 * @rc: the response fcall structure
84 * @aux: transport specific data (provided for trans_fd migration)
85 * @req_list: link for higher level objects to chain requests
86 *
87 * Transport use an array to track outstanding requests
88 * instead of a list. While this may incurr overhead during initial
89 * allocation or expansion, it makes request lookup much easier as the
90 * tag id is a index into an array. (We use tag+1 so that we can accomodate
91 * the -1 tag for the T_VERSION request).
92 * This also has the nice effect of only having to allocate wait_queues
93 * once, instead of constantly allocating and freeing them. Its possible
94 * other resources could benefit from this scheme as well.
95 *
96 */
97
98struct p9_req_t {
99 int status;
100 int t_err;
101 u16 flush_tag;
102 wait_queue_head_t *wq;
103 struct p9_fcall *tc;
104 struct p9_fcall *rc;
105 void *aux;
106
107 struct list_head req_list;
108};
109
29/** 110/**
30 * struct p9_client - per client instance state 111 * struct p9_client - per client instance state
31 * @lock: protect @fidlist 112 * @lock: protect @fidlist
@@ -36,9 +117,20 @@
36 * @conn: connection state information used by trans_fd 117 * @conn: connection state information used by trans_fd
37 * @fidpool: fid handle accounting for session 118 * @fidpool: fid handle accounting for session
38 * @fidlist: List of active fid handles 119 * @fidlist: List of active fid handles
120 * @tagpool - transaction id accounting for session
121 * @reqs - 2D array of requests
122 * @max_tag - current maximum tag id allocated
39 * 123 *
40 * The client structure is used to keep track of various per-client 124 * The client structure is used to keep track of various per-client
41 * state that has been instantiated. 125 * state that has been instantiated.
126 * In order to minimize per-transaction overhead we use a
127 * simple array to lookup requests instead of a hash table
128 * or linked list. In order to support larger number of
129 * transactions, we make this a 2D array, allocating new rows
130 * when we need to grow the total number of the transactions.
131 *
132 * Each row is 256 requests and we'll support up to 256 rows for
133 * a total of 64k concurrent requests per session.
42 * 134 *
43 * Bugs: duplicated data and potentially unnecessary elements. 135 * Bugs: duplicated data and potentially unnecessary elements.
44 */ 136 */
@@ -48,11 +140,16 @@ struct p9_client {
48 int msize; 140 int msize;
49 unsigned char dotu; 141 unsigned char dotu;
50 struct p9_trans_module *trans_mod; 142 struct p9_trans_module *trans_mod;
51 struct p9_trans *trans; 143 enum p9_trans_status status;
144 void *trans;
52 struct p9_conn *conn; 145 struct p9_conn *conn;
53 146
54 struct p9_idpool *fidpool; 147 struct p9_idpool *fidpool;
55 struct list_head fidlist; 148 struct list_head fidlist;
149
150 struct p9_idpool *tagpool;
151 struct p9_req_t *reqs[P9_ROW_MAXTAG];
152 int max_tag;
56}; 153};
57 154
58/** 155/**
@@ -65,8 +162,6 @@ struct p9_client {
65 * @uid: the numeric uid of the local user who owns this handle 162 * @uid: the numeric uid of the local user who owns this handle
66 * @aux: transport specific information (unused?) 163 * @aux: transport specific information (unused?)
67 * @rdir_fpos: tracks offset of file position when reading directory contents 164 * @rdir_fpos: tracks offset of file position when reading directory contents
68 * @rdir_pos: (unused?)
69 * @rdir_fcall: holds response of last directory read request
70 * @flist: per-client-instance fid tracking 165 * @flist: per-client-instance fid tracking
71 * @dlist: per-dentry fid tracking 166 * @dlist: per-dentry fid tracking
72 * 167 *
@@ -83,8 +178,6 @@ struct p9_fid {
83 void *aux; 178 void *aux;
84 179
85 int rdir_fpos; 180 int rdir_fpos;
86 int rdir_pos;
87 struct p9_fcall *rdir_fcall;
88 struct list_head flist; 181 struct list_head flist;
89 struct list_head dlist; /* list of all fids attached to a dentry */ 182 struct list_head dlist; /* list of all fids attached to a dentry */
90}; 183};
@@ -103,15 +196,18 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
103 char *extension); 196 char *extension);
104int p9_client_clunk(struct p9_fid *fid); 197int p9_client_clunk(struct p9_fid *fid);
105int p9_client_remove(struct p9_fid *fid); 198int p9_client_remove(struct p9_fid *fid);
106int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count); 199int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
107int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count); 200 u64 offset, u32 count);
108int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count); 201int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
109int p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, 202 u64 offset, u32 count);
110 u32 count); 203struct p9_wstat *p9_client_stat(struct p9_fid *fid);
111int p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
112 u32 count);
113struct p9_stat *p9_client_stat(struct p9_fid *fid);
114int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst); 204int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
115struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset); 205
206struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
207void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
208
209int p9stat_read(char *, int, struct p9_wstat *, int);
210void p9stat_free(struct p9_wstat *);
211
116 212
117#endif /* NET_9P_CLIENT_H */ 213#endif /* NET_9P_CLIENT_H */
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
index 3ca737120a90..6d5886efb102 100644
--- a/include/net/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -26,52 +26,6 @@
26#ifndef NET_9P_TRANSPORT_H 26#ifndef NET_9P_TRANSPORT_H
27#define NET_9P_TRANSPORT_H 27#define NET_9P_TRANSPORT_H
28 28
29#include <linux/module.h>
30
31/**
32 * enum p9_trans_status - different states of underlying transports
33 * @Connected: transport is connected and healthy
34 * @Disconnected: transport has been disconnected
35 * @Hung: transport is connected by wedged
36 *
37 * This enumeration details the various states a transport
38 * instatiation can be in.
39 */
40
41enum p9_trans_status {
42 Connected,
43 Disconnected,
44 Hung,
45};
46
47/**
48 * struct p9_trans - per-transport state and API
49 * @status: transport &p9_trans_status
50 * @msize: negotiated maximum packet size (duplicate from client)
51 * @extended: negotiated protocol extensions (duplicate from client)
52 * @priv: transport private data
53 * @close: member function to disconnect and close the transport
54 * @rpc: member function to issue a request to the transport
55 *
56 * This is the basic API for a transport instance. It is used as
57 * a handle by the client to issue requests. This interface is currently
58 * in flux during reorganization.
59 *
60 * Bugs: there is lots of duplicated data here and its not clear that
61 * the member functions need to be per-instance versus per transport
62 * module.
63 */
64
65struct p9_trans {
66 enum p9_trans_status status;
67 int msize;
68 unsigned char extended;
69 void *priv;
70 void (*close) (struct p9_trans *);
71 int (*rpc) (struct p9_trans *t, struct p9_fcall *tc,
72 struct p9_fcall **rc);
73};
74
75/** 29/**
76 * struct p9_trans_module - transport module interface 30 * struct p9_trans_module - transport module interface
77 * @list: used to maintain a list of currently available transports 31 * @list: used to maintain a list of currently available transports
@@ -79,12 +33,14 @@ struct p9_trans {
79 * @maxsize: transport provided maximum packet size 33 * @maxsize: transport provided maximum packet size
80 * @def: set if this transport should be considered the default 34 * @def: set if this transport should be considered the default
81 * @create: member function to create a new connection on this transport 35 * @create: member function to create a new connection on this transport
36 * @request: member function to issue a request to the transport
37 * @cancel: member function to cancel a request (if it hasn't been sent)
82 * 38 *
83 * This is the basic API for a transport module which is registered by the 39 * This is the basic API for a transport module which is registered by the
84 * transport module with the 9P core network module and used by the client 40 * transport module with the 9P core network module and used by the client
85 * to instantiate a new connection on a transport. 41 * to instantiate a new connection on a transport.
86 * 42 *
87 * Bugs: the transport module list isn't protected. 43 * BUGS: the transport module list isn't protected.
88 */ 44 */
89 45
90struct p9_trans_module { 46struct p9_trans_module {
@@ -92,8 +48,11 @@ struct p9_trans_module {
92 char *name; /* name of transport */ 48 char *name; /* name of transport */
93 int maxsize; /* max message size of transport */ 49 int maxsize; /* max message size of transport */
94 int def; /* this transport should be default */ 50 int def; /* this transport should be default */
95 struct p9_trans * (*create)(const char *, char *, int, unsigned char);
96 struct module *owner; 51 struct module *owner;
52 int (*create)(struct p9_client *, const char *, char *);
53 void (*close) (struct p9_client *);
54 int (*request) (struct p9_client *, struct p9_req_t *req);
55 int (*cancel) (struct p9_client *, struct p9_req_t *req);
97}; 56};
98 57
99void v9fs_register_trans(struct p9_trans_module *m); 58void v9fs_register_trans(struct p9_trans_module *m);
diff --git a/net/9p/Makefile b/net/9p/Makefile
index 519219480db1..1041b7bd12e2 100644
--- a/net/9p/Makefile
+++ b/net/9p/Makefile
@@ -4,10 +4,9 @@ obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o
49pnet-objs := \ 49pnet-objs := \
5 mod.o \ 5 mod.o \
6 client.o \ 6 client.o \
7 conv.o \
8 error.o \ 7 error.o \
9 fcprint.o \
10 util.o \ 8 util.o \
9 protocol.o \
11 trans_fd.o \ 10 trans_fd.o \
12 11
139pnet_virtio-objs := \ 129pnet_virtio-objs := \
diff --git a/net/9p/client.c b/net/9p/client.c
index e053e06028a5..bbac2f72b4d2 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -33,12 +33,9 @@
33#include <linux/uaccess.h> 33#include <linux/uaccess.h>
34#include <net/9p/9p.h> 34#include <net/9p/9p.h>
35#include <linux/parser.h> 35#include <linux/parser.h>
36#include <net/9p/transport.h>
37#include <net/9p/client.h> 36#include <net/9p/client.h>
38 37#include <net/9p/transport.h>
39static struct p9_fid *p9_fid_create(struct p9_client *clnt); 38#include "protocol.h"
40static void p9_fid_destroy(struct p9_fid *fid);
41static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
42 39
43/* 40/*
44 * Client Option Parsing (code inspired by NFS code) 41 * Client Option Parsing (code inspired by NFS code)
@@ -59,6 +56,9 @@ static const match_table_t tokens = {
59 {Opt_err, NULL}, 56 {Opt_err, NULL},
60}; 57};
61 58
59static struct p9_req_t *
60p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
61
62/** 62/**
63 * v9fs_parse_options - parse mount options into session structure 63 * v9fs_parse_options - parse mount options into session structure
64 * @options: options string passed from mount 64 * @options: options string passed from mount
@@ -124,31 +124,585 @@ static int parse_opts(char *opts, struct p9_client *clnt)
124 return ret; 124 return ret;
125} 125}
126 126
127/**
128 * p9_tag_alloc - lookup/allocate a request by tag
129 * @c: client session to lookup tag within
130 * @tag: numeric id for transaction
131 *
132 * this is a simple array lookup, but will grow the
133 * request_slots as necessary to accomodate transaction
134 * ids which did not previously have a slot.
135 *
136 * this code relies on the client spinlock to manage locks, its
137 * possible we should switch to something else, but I'd rather
138 * stick with something low-overhead for the common case.
139 *
140 */
141
142static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
143{
144 unsigned long flags;
145 int row, col;
146 struct p9_req_t *req;
147
148 /* This looks up the original request by tag so we know which
149 * buffer to read the data into */
150 tag++;
151
152 if (tag >= c->max_tag) {
153 spin_lock_irqsave(&c->lock, flags);
154 /* check again since original check was outside of lock */
155 while (tag >= c->max_tag) {
156 row = (tag / P9_ROW_MAXTAG);
157 c->reqs[row] = kcalloc(P9_ROW_MAXTAG,
158 sizeof(struct p9_req_t), GFP_ATOMIC);
159
160 if (!c->reqs[row]) {
161 printk(KERN_ERR "Couldn't grow tag array\n");
162 return ERR_PTR(-ENOMEM);
163 }
164 for (col = 0; col < P9_ROW_MAXTAG; col++) {
165 c->reqs[row][col].status = REQ_STATUS_IDLE;
166 c->reqs[row][col].tc = NULL;
167 }
168 c->max_tag += P9_ROW_MAXTAG;
169 }
170 spin_unlock_irqrestore(&c->lock, flags);
171 }
172 row = tag / P9_ROW_MAXTAG;
173 col = tag % P9_ROW_MAXTAG;
174
175 req = &c->reqs[row][col];
176 if (!req->tc) {
177 req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
178 if (!req->wq) {
179 printk(KERN_ERR "Couldn't grow tag array\n");
180 return ERR_PTR(-ENOMEM);
181 }
182 init_waitqueue_head(req->wq);
183 req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize,
184 GFP_KERNEL);
185 req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize,
186 GFP_KERNEL);
187 if ((!req->tc) || (!req->rc)) {
188 printk(KERN_ERR "Couldn't grow tag array\n");
189 kfree(req->tc);
190 kfree(req->rc);
191 return ERR_PTR(-ENOMEM);
192 }
193 req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall);
194 req->tc->capacity = c->msize;
195 req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall);
196 req->rc->capacity = c->msize;
197 }
198
199 p9pdu_reset(req->tc);
200 p9pdu_reset(req->rc);
201
202 req->flush_tag = 0;
203 req->tc->tag = tag-1;
204 req->status = REQ_STATUS_ALLOC;
205
206 return &c->reqs[row][col];
207}
208
209/**
210 * p9_tag_lookup - lookup a request by tag
211 * @c: client session to lookup tag within
212 * @tag: numeric id for transaction
213 *
214 */
215
216struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
217{
218 int row, col;
219
220 /* This looks up the original request by tag so we know which
221 * buffer to read the data into */
222 tag++;
223
224 BUG_ON(tag >= c->max_tag);
225
226 row = tag / P9_ROW_MAXTAG;
227 col = tag % P9_ROW_MAXTAG;
228
229 return &c->reqs[row][col];
230}
231EXPORT_SYMBOL(p9_tag_lookup);
232
233/**
234 * p9_tag_init - setup tags structure and contents
235 * @tags: tags structure from the client struct
236 *
237 * This initializes the tags structure for each client instance.
238 *
239 */
240
241static int p9_tag_init(struct p9_client *c)
242{
243 int err = 0;
244
245 c->tagpool = p9_idpool_create();
246 if (IS_ERR(c->tagpool)) {
247 err = PTR_ERR(c->tagpool);
248 c->tagpool = NULL;
249 goto error;
250 }
251
252 p9_idpool_get(c->tagpool); /* reserve tag 0 */
253
254 c->max_tag = 0;
255error:
256 return err;
257}
127 258
128/** 259/**
129 * p9_client_rpc - sends 9P request and waits until a response is available. 260 * p9_tag_cleanup - cleans up tags structure and reclaims resources
130 * The function can be interrupted. 261 * @tags: tags structure from the client struct
131 * @c: client data 262 *
132 * @tc: request to be sent 263 * This frees resources associated with the tags structure
133 * @rc: pointer where a pointer to the response is stored 264 *
134 */ 265 */
266static void p9_tag_cleanup(struct p9_client *c)
267{
268 int row, col;
269
270 /* check to insure all requests are idle */
271 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
272 for (col = 0; col < P9_ROW_MAXTAG; col++) {
273 if (c->reqs[row][col].status != REQ_STATUS_IDLE) {
274 P9_DPRINTK(P9_DEBUG_MUX,
275 "Attempting to cleanup non-free tag %d,%d\n",
276 row, col);
277 /* TODO: delay execution of cleanup */
278 return;
279 }
280 }
281 }
282
283 if (c->tagpool)
284 p9_idpool_destroy(c->tagpool);
285
286 /* free requests associated with tags */
287 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
288 for (col = 0; col < P9_ROW_MAXTAG; col++) {
289 kfree(c->reqs[row][col].wq);
290 kfree(c->reqs[row][col].tc);
291 kfree(c->reqs[row][col].rc);
292 }
293 kfree(c->reqs[row]);
294 }
295 c->max_tag = 0;
296}
297
298/**
299 * p9_free_req - free a request and clean-up as necessary
300 * c: client state
301 * r: request to release
302 *
303 */
304
305static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
306{
307 int tag = r->tc->tag;
308 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag);
309
310 r->status = REQ_STATUS_IDLE;
311 if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool))
312 p9_idpool_put(tag, c->tagpool);
313
314 /* if this was a flush request we have to free response fcall */
315 if (r->rc->id == P9_RFLUSH) {
316 kfree(r->tc);
317 kfree(r->rc);
318 }
319}
320
321/**
322 * p9_client_cb - call back from transport to client
323 * c: client state
324 * req: request received
325 *
326 */
327void p9_client_cb(struct p9_client *c, struct p9_req_t *req)
328{
329 struct p9_req_t *other_req;
330 unsigned long flags;
331
332 P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag);
333
334 if (req->status == REQ_STATUS_ERROR)
335 wake_up(req->wq);
336
337 if (req->flush_tag) { /* flush receive path */
338 P9_DPRINTK(P9_DEBUG_9P, "<<< RFLUSH %d\n", req->tc->tag);
339 spin_lock_irqsave(&c->lock, flags);
340 other_req = p9_tag_lookup(c, req->flush_tag);
341 if (other_req->status != REQ_STATUS_FLSH) /* stale flush */
342 spin_unlock_irqrestore(&c->lock, flags);
343 else {
344 other_req->status = REQ_STATUS_FLSHD;
345 spin_unlock_irqrestore(&c->lock, flags);
346 wake_up(other_req->wq);
347 }
348 p9_free_req(c, req);
349 } else { /* normal receive path */
350 P9_DPRINTK(P9_DEBUG_MUX, "normal: tag %d\n", req->tc->tag);
351 spin_lock_irqsave(&c->lock, flags);
352 if (req->status != REQ_STATUS_FLSHD)
353 req->status = REQ_STATUS_RCVD;
354 spin_unlock_irqrestore(&c->lock, flags);
355 wake_up(req->wq);
356 P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
357 }
358}
359EXPORT_SYMBOL(p9_client_cb);
360
361/**
362 * p9_parse_header - parse header arguments out of a packet
363 * @pdu: packet to parse
364 * @size: size of packet
365 * @type: type of request
366 * @tag: tag of packet
367 * @rewind: set if we need to rewind offset afterwards
368 */
369
135int 370int
136p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, 371p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag,
137 struct p9_fcall **rc) 372 int rewind)
138{ 373{
139 return c->trans->rpc(c->trans, tc, rc); 374 int8_t r_type;
375 int16_t r_tag;
376 int32_t r_size;
377 int offset = pdu->offset;
378 int err;
379
380 pdu->offset = 0;
381 if (pdu->size == 0)
382 pdu->size = 7;
383
384 err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag);
385 if (err)
386 goto rewind_and_exit;
387
388 pdu->size = r_size;
389 pdu->id = r_type;
390 pdu->tag = r_tag;
391
392 P9_DPRINTK(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", pdu->size,
393 pdu->id, pdu->tag);
394
395 if (type)
396 *type = r_type;
397 if (tag)
398 *tag = r_tag;
399 if (size)
400 *size = r_size;
401
402
403rewind_and_exit:
404 if (rewind)
405 pdu->offset = offset;
406 return err;
140} 407}
408EXPORT_SYMBOL(p9_parse_header);
409
410/**
411 * p9_check_errors - check 9p packet for error return and process it
412 * @c: current client instance
413 * @req: request to parse and check for error conditions
414 *
415 * returns error code if one is discovered, otherwise returns 0
416 *
417 * this will have to be more complicated if we have multiple
418 * error packet types
419 */
420
421static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
422{
423 int8_t type;
424 int err;
425
426 err = p9_parse_header(req->rc, NULL, &type, NULL, 0);
427 if (err) {
428 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
429 return err;
430 }
431
432 if (type == P9_RERROR) {
433 int ecode;
434 char *ename;
435
436 err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode);
437 if (err) {
438 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
439 err);
440 return err;
441 }
442
443 if (c->dotu)
444 err = -ecode;
445
446 if (!err) {
447 err = p9_errstr2errno(ename, strlen(ename));
448
449 /* string match failed */
450 if (!err)
451 err = -ESERVERFAULT;
452 }
453
454 P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename);
455
456 kfree(ename);
457 } else
458 err = 0;
459
460 return err;
461}
462
463/**
464 * p9_client_flush - flush (cancel) a request
465 * c: client state
466 * req: request to cancel
467 *
468 * This sents a flush for a particular requests and links
469 * the flush request to the original request. The current
470 * code only supports a single flush request although the protocol
471 * allows for multiple flush requests to be sent for a single request.
472 *
473 */
474
475static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
476{
477 struct p9_req_t *req;
478 int16_t oldtag;
479 int err;
480
481 err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1);
482 if (err)
483 return err;
484
485 P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);
486
487 req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag);
488 if (IS_ERR(req))
489 return PTR_ERR(req);
490
491 req->flush_tag = oldtag;
492
493 /* we don't free anything here because RPC isn't complete */
494 return 0;
495}
496
497/**
498 * p9_client_rpc - issue a request and wait for a response
499 * @c: client session
500 * @type: type of request
501 * @fmt: protocol format string (see protocol.c)
502 *
503 * Returns request structure (which client must free using p9_free_req)
504 */
505
506static struct p9_req_t *
507p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
508{
509 va_list ap;
510 int tag, err;
511 struct p9_req_t *req;
512 unsigned long flags;
513 int sigpending;
514 int flushed = 0;
515
516 P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);
517
518 if (c->status != Connected)
519 return ERR_PTR(-EIO);
520
521 if (signal_pending(current)) {
522 sigpending = 1;
523 clear_thread_flag(TIF_SIGPENDING);
524 } else
525 sigpending = 0;
526
527 tag = P9_NOTAG;
528 if (type != P9_TVERSION) {
529 tag = p9_idpool_get(c->tagpool);
530 if (tag < 0)
531 return ERR_PTR(-ENOMEM);
532 }
533
534 req = p9_tag_alloc(c, tag);
535 if (IS_ERR(req))
536 return req;
537
538 /* marshall the data */
539 p9pdu_prepare(req->tc, tag, type);
540 va_start(ap, fmt);
541 err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap);
542 va_end(ap);
543 p9pdu_finalize(req->tc);
544
545 err = c->trans_mod->request(c, req);
546 if (err < 0) {
547 c->status = Disconnected;
548 goto reterr;
549 }
550
551 /* if it was a flush we just transmitted, return our tag */
552 if (type == P9_TFLUSH)
553 return req;
554again:
555 P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag);
556 err = wait_event_interruptible(*req->wq,
557 req->status >= REQ_STATUS_RCVD);
558 P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d (flushed=%d)\n",
559 req->wq, tag, err, flushed);
560
561 if (req->status == REQ_STATUS_ERROR) {
562 P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
563 err = req->t_err;
564 } else if (err == -ERESTARTSYS && flushed) {
565 P9_DPRINTK(P9_DEBUG_MUX, "flushed - going again\n");
566 goto again;
567 } else if (req->status == REQ_STATUS_FLSHD) {
568 P9_DPRINTK(P9_DEBUG_MUX, "flushed - erestartsys\n");
569 err = -ERESTARTSYS;
570 }
571
572 if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) {
573 P9_DPRINTK(P9_DEBUG_MUX, "flushing\n");
574 spin_lock_irqsave(&c->lock, flags);
575 if (req->status == REQ_STATUS_SENT)
576 req->status = REQ_STATUS_FLSH;
577 spin_unlock_irqrestore(&c->lock, flags);
578 sigpending = 1;
579 flushed = 1;
580 clear_thread_flag(TIF_SIGPENDING);
581
582 if (c->trans_mod->cancel(c, req)) {
583 err = p9_client_flush(c, req);
584 if (err == 0)
585 goto again;
586 }
587 }
588
589 if (sigpending) {
590 spin_lock_irqsave(&current->sighand->siglock, flags);
591 recalc_sigpending();
592 spin_unlock_irqrestore(&current->sighand->siglock, flags);
593 }
594
595 if (err < 0)
596 goto reterr;
597
598 err = p9_check_errors(c, req);
599 if (!err) {
600 P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type);
601 return req;
602 }
603
604reterr:
605 P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type,
606 err);
607 p9_free_req(c, req);
608 return ERR_PTR(err);
609}
610
611static struct p9_fid *p9_fid_create(struct p9_client *clnt)
612{
613 int err;
614 struct p9_fid *fid;
615
616 P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt);
617 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
618 if (!fid)
619 return ERR_PTR(-ENOMEM);
620
621 fid->fid = p9_idpool_get(clnt->fidpool);
622 if (fid->fid < 0) {
623 err = -ENOSPC;
624 goto error;
625 }
626
627 memset(&fid->qid, 0, sizeof(struct p9_qid));
628 fid->mode = -1;
629 fid->rdir_fpos = 0;
630 fid->uid = current->fsuid;
631 fid->clnt = clnt;
632 fid->aux = NULL;
633
634 spin_lock(&clnt->lock);
635 list_add(&fid->flist, &clnt->fidlist);
636 spin_unlock(&clnt->lock);
637
638 return fid;
639
640error:
641 kfree(fid);
642 return ERR_PTR(err);
643}
644
645static void p9_fid_destroy(struct p9_fid *fid)
646{
647 struct p9_client *clnt;
648
649 P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid);
650 clnt = fid->clnt;
651 p9_idpool_put(fid->fid, clnt->fidpool);
652 spin_lock(&clnt->lock);
653 list_del(&fid->flist);
654 spin_unlock(&clnt->lock);
655 kfree(fid);
656}
657
658int p9_client_version(struct p9_client *c)
659{
660 int err = 0;
661 struct p9_req_t *req;
662 char *version;
663 int msize;
664
665 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n",
666 c->msize, c->dotu);
667 req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize,
668 c->dotu ? "9P2000.u" : "9P2000");
669 if (IS_ERR(req))
670 return PTR_ERR(req);
671
672 err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version);
673 if (err) {
674 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
675 p9pdu_dump(1, req->rc);
676 goto error;
677 }
678
679 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
680 if (!memcmp(version, "9P2000.u", 8))
681 c->dotu = 1;
682 else if (!memcmp(version, "9P2000", 6))
683 c->dotu = 0;
684 else {
685 err = -EREMOTEIO;
686 goto error;
687 }
688
689 if (msize < c->msize)
690 c->msize = msize;
691
692error:
693 kfree(version);
694 p9_free_req(c, req);
695
696 return err;
697}
698EXPORT_SYMBOL(p9_client_version);
141 699
142struct p9_client *p9_client_create(const char *dev_name, char *options) 700struct p9_client *p9_client_create(const char *dev_name, char *options)
143{ 701{
144 int err, n; 702 int err;
145 struct p9_client *clnt; 703 struct p9_client *clnt;
146 struct p9_fcall *tc, *rc;
147 struct p9_str *version;
148 704
149 err = 0; 705 err = 0;
150 tc = NULL;
151 rc = NULL;
152 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); 706 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
153 if (!clnt) 707 if (!clnt)
154 return ERR_PTR(-ENOMEM); 708 return ERR_PTR(-ENOMEM);
@@ -164,6 +718,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
164 goto error; 718 goto error;
165 } 719 }
166 720
721 p9_tag_init(clnt);
722
167 err = parse_opts(options, clnt); 723 err = parse_opts(options, clnt);
168 if (err < 0) 724 if (err < 0)
169 goto error; 725 goto error;
@@ -175,53 +731,23 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
175 goto error; 731 goto error;
176 } 732 }
177 733
178 P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n", 734 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n",
179 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 735 clnt, clnt->trans_mod, clnt->msize, clnt->dotu);
180 736
181 737 err = clnt->trans_mod->create(clnt, dev_name, options);
182 clnt->trans = clnt->trans_mod->create(dev_name, options, clnt->msize, 738 if (err)
183 clnt->dotu);
184 if (IS_ERR(clnt->trans)) {
185 err = PTR_ERR(clnt->trans);
186 clnt->trans = NULL;
187 goto error; 739 goto error;
188 }
189 740
190 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) 741 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
191 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; 742 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
192 743
193 tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000"); 744 err = p9_client_version(clnt);
194 if (IS_ERR(tc)) {
195 err = PTR_ERR(tc);
196 tc = NULL;
197 goto error;
198 }
199
200 err = p9_client_rpc(clnt, tc, &rc);
201 if (err) 745 if (err)
202 goto error; 746 goto error;
203 747
204 version = &rc->params.rversion.version;
205 if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
206 clnt->dotu = 1;
207 else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
208 clnt->dotu = 0;
209 else {
210 err = -EREMOTEIO;
211 goto error;
212 }
213
214 n = rc->params.rversion.msize;
215 if (n < clnt->msize)
216 clnt->msize = n;
217
218 kfree(tc);
219 kfree(rc);
220 return clnt; 748 return clnt;
221 749
222error: 750error:
223 kfree(tc);
224 kfree(rc);
225 p9_client_destroy(clnt); 751 p9_client_destroy(clnt);
226 return ERR_PTR(err); 752 return ERR_PTR(err);
227} 753}
@@ -231,13 +757,10 @@ void p9_client_destroy(struct p9_client *clnt)
231{ 757{
232 struct p9_fid *fid, *fidptr; 758 struct p9_fid *fid, *fidptr;
233 759
234 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 760 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt);
235 761
236 if (clnt->trans) { 762 if (clnt->trans_mod)
237 clnt->trans->close(clnt->trans); 763 clnt->trans_mod->close(clnt);
238 kfree(clnt->trans);
239 clnt->trans = NULL;
240 }
241 764
242 v9fs_put_trans(clnt->trans_mod); 765 v9fs_put_trans(clnt->trans_mod);
243 766
@@ -247,6 +770,8 @@ void p9_client_destroy(struct p9_client *clnt)
247 if (clnt->fidpool) 770 if (clnt->fidpool)
248 p9_idpool_destroy(clnt->fidpool); 771 p9_idpool_destroy(clnt->fidpool);
249 772
773 p9_tag_cleanup(clnt);
774
250 kfree(clnt); 775 kfree(clnt);
251} 776}
252EXPORT_SYMBOL(p9_client_destroy); 777EXPORT_SYMBOL(p9_client_destroy);
@@ -254,7 +779,7 @@ EXPORT_SYMBOL(p9_client_destroy);
254void p9_client_disconnect(struct p9_client *clnt) 779void p9_client_disconnect(struct p9_client *clnt)
255{ 780{
256 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 781 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
257 clnt->trans->status = Disconnected; 782 clnt->status = Disconnected;
258} 783}
259EXPORT_SYMBOL(p9_client_disconnect); 784EXPORT_SYMBOL(p9_client_disconnect);
260 785
@@ -262,14 +787,13 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
262 char *uname, u32 n_uname, char *aname) 787 char *uname, u32 n_uname, char *aname)
263{ 788{
264 int err; 789 int err;
265 struct p9_fcall *tc, *rc; 790 struct p9_req_t *req;
266 struct p9_fid *fid; 791 struct p9_fid *fid;
792 struct p9_qid qid;
267 793
268 P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n", 794 P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
269 clnt, afid?afid->fid:-1, uname, aname); 795 afid ? afid->fid : -1, uname, aname);
270 err = 0; 796 err = 0;
271 tc = NULL;
272 rc = NULL;
273 797
274 fid = p9_fid_create(clnt); 798 fid = p9_fid_create(clnt);
275 if (IS_ERR(fid)) { 799 if (IS_ERR(fid)) {
@@ -278,73 +802,77 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
278 goto error; 802 goto error;
279 } 803 }
280 804
281 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname, 805 req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid,
282 n_uname, clnt->dotu); 806 afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
283 if (IS_ERR(tc)) { 807 if (IS_ERR(req)) {
284 err = PTR_ERR(tc); 808 err = PTR_ERR(req);
285 tc = NULL;
286 goto error; 809 goto error;
287 } 810 }
288 811
289 err = p9_client_rpc(clnt, tc, &rc); 812 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid);
290 if (err) 813 if (err) {
814 p9pdu_dump(1, req->rc);
815 p9_free_req(clnt, req);
291 goto error; 816 goto error;
817 }
818
819 P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n",
820 qid.type, qid.path, qid.version);
292 821
293 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid)); 822 memmove(&fid->qid, &qid, sizeof(struct p9_qid));
294 kfree(tc); 823
295 kfree(rc); 824 p9_free_req(clnt, req);
296 return fid; 825 return fid;
297 826
298error: 827error:
299 kfree(tc);
300 kfree(rc);
301 if (fid) 828 if (fid)
302 p9_fid_destroy(fid); 829 p9_fid_destroy(fid);
303 return ERR_PTR(err); 830 return ERR_PTR(err);
304} 831}
305EXPORT_SYMBOL(p9_client_attach); 832EXPORT_SYMBOL(p9_client_attach);
306 833
307struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, 834struct p9_fid *
308 u32 n_uname, char *aname) 835p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
309{ 836{
310 int err; 837 int err;
311 struct p9_fcall *tc, *rc; 838 struct p9_req_t *req;
312 struct p9_fid *fid; 839 struct p9_qid qid;
840 struct p9_fid *afid;
313 841
314 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname, 842 P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname);
315 aname);
316 err = 0; 843 err = 0;
317 tc = NULL;
318 rc = NULL;
319 844
320 fid = p9_fid_create(clnt); 845 afid = p9_fid_create(clnt);
321 if (IS_ERR(fid)) { 846 if (IS_ERR(afid)) {
322 err = PTR_ERR(fid); 847 err = PTR_ERR(afid);
323 fid = NULL; 848 afid = NULL;
324 goto error; 849 goto error;
325 } 850 }
326 851
327 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu); 852 req = p9_client_rpc(clnt, P9_TAUTH, "dss?d",
328 if (IS_ERR(tc)) { 853 afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
329 err = PTR_ERR(tc); 854 if (IS_ERR(req)) {
330 tc = NULL; 855 err = PTR_ERR(req);
331 goto error; 856 goto error;
332 } 857 }
333 858
334 err = p9_client_rpc(clnt, tc, &rc); 859 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid);
335 if (err) 860 if (err) {
861 p9pdu_dump(1, req->rc);
862 p9_free_req(clnt, req);
336 goto error; 863 goto error;
864 }
337 865
338 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid)); 866 P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n",
339 kfree(tc); 867 qid.type, qid.path, qid.version);
340 kfree(rc); 868
341 return fid; 869 memmove(&afid->qid, &qid, sizeof(struct p9_qid));
870 p9_free_req(clnt, req);
871 return afid;
342 872
343error: 873error:
344 kfree(tc); 874 if (afid)
345 kfree(rc); 875 p9_fid_destroy(afid);
346 if (fid)
347 p9_fid_destroy(fid);
348 return ERR_PTR(err); 876 return ERR_PTR(err);
349} 877}
350EXPORT_SYMBOL(p9_client_auth); 878EXPORT_SYMBOL(p9_client_auth);
@@ -353,15 +881,13 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
353 int clone) 881 int clone)
354{ 882{
355 int err; 883 int err;
356 struct p9_fcall *tc, *rc;
357 struct p9_client *clnt; 884 struct p9_client *clnt;
358 struct p9_fid *fid; 885 struct p9_fid *fid;
886 struct p9_qid *wqids;
887 struct p9_req_t *req;
888 int16_t nwqids, count;
359 889
360 P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
361 oldfid->fid, nwname, wnames?wnames[0]:NULL);
362 err = 0; 890 err = 0;
363 tc = NULL;
364 rc = NULL;
365 clnt = oldfid->clnt; 891 clnt = oldfid->clnt;
366 if (clone) { 892 if (clone) {
367 fid = p9_fid_create(clnt); 893 fid = p9_fid_create(clnt);
@@ -375,53 +901,49 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
375 } else 901 } else
376 fid = oldfid; 902 fid = oldfid;
377 903
378 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames); 904
379 if (IS_ERR(tc)) { 905 P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n",
380 err = PTR_ERR(tc); 906 oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
381 tc = NULL; 907
908 req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
909 nwname, wnames);
910 if (IS_ERR(req)) {
911 err = PTR_ERR(req);
382 goto error; 912 goto error;
383 } 913 }
384 914
385 err = p9_client_rpc(clnt, tc, &rc); 915 err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids);
386 if (err) { 916 if (err) {
387 if (rc && rc->id == P9_RWALK) 917 p9pdu_dump(1, req->rc);
388 goto clunk_fid; 918 p9_free_req(clnt, req);
389 else 919 goto clunk_fid;
390 goto error;
391 } 920 }
921 p9_free_req(clnt, req);
392 922
393 if (rc->params.rwalk.nwqid != nwname) { 923 P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids);
924
925 if (nwqids != nwname) {
394 err = -ENOENT; 926 err = -ENOENT;
395 goto clunk_fid; 927 goto clunk_fid;
396 } 928 }
397 929
930 for (count = 0; count < nwqids; count++)
931 P9_DPRINTK(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n",
932 count, wqids[count].type, wqids[count].path,
933 wqids[count].version);
934
398 if (nwname) 935 if (nwname)
399 memmove(&fid->qid, 936 memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid));
400 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
401 sizeof(struct p9_qid));
402 else 937 else
403 fid->qid = oldfid->qid; 938 fid->qid = oldfid->qid;
404 939
405 kfree(tc);
406 kfree(rc);
407 return fid; 940 return fid;
408 941
409clunk_fid: 942clunk_fid:
410 kfree(tc); 943 p9_client_clunk(fid);
411 kfree(rc); 944 fid = NULL;
412 rc = NULL;
413 tc = p9_create_tclunk(fid->fid);
414 if (IS_ERR(tc)) {
415 err = PTR_ERR(tc);
416 tc = NULL;
417 goto error;
418 }
419
420 p9_client_rpc(clnt, tc, &rc);
421 945
422error: 946error:
423 kfree(tc);
424 kfree(rc);
425 if (fid && (fid != oldfid)) 947 if (fid && (fid != oldfid))
426 p9_fid_destroy(fid); 948 p9_fid_destroy(fid);
427 949
@@ -432,35 +954,39 @@ EXPORT_SYMBOL(p9_client_walk);
432int p9_client_open(struct p9_fid *fid, int mode) 954int p9_client_open(struct p9_fid *fid, int mode)
433{ 955{
434 int err; 956 int err;
435 struct p9_fcall *tc, *rc;
436 struct p9_client *clnt; 957 struct p9_client *clnt;
958 struct p9_req_t *req;
959 struct p9_qid qid;
960 int iounit;
437 961
438 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode); 962 P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode);
439 err = 0; 963 err = 0;
440 tc = NULL;
441 rc = NULL;
442 clnt = fid->clnt; 964 clnt = fid->clnt;
443 965
444 if (fid->mode != -1) 966 if (fid->mode != -1)
445 return -EINVAL; 967 return -EINVAL;
446 968
447 tc = p9_create_topen(fid->fid, mode); 969 req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode);
448 if (IS_ERR(tc)) { 970 if (IS_ERR(req)) {
449 err = PTR_ERR(tc); 971 err = PTR_ERR(req);
450 tc = NULL; 972 goto error;
451 goto done;
452 } 973 }
453 974
454 err = p9_client_rpc(clnt, tc, &rc); 975 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit);
455 if (err) 976 if (err) {
456 goto done; 977 p9pdu_dump(1, req->rc);
978 goto free_and_error;
979 }
980
981 P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n",
982 qid.type, qid.path, qid.version, iounit);
457 983
458 fid->mode = mode; 984 fid->mode = mode;
459 fid->iounit = rc->params.ropen.iounit; 985 fid->iounit = iounit;
460 986
461done: 987free_and_error:
462 kfree(tc); 988 p9_free_req(clnt, req);
463 kfree(rc); 989error:
464 return err; 990 return err;
465} 991}
466EXPORT_SYMBOL(p9_client_open); 992EXPORT_SYMBOL(p9_client_open);
@@ -469,37 +995,41 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
469 char *extension) 995 char *extension)
470{ 996{
471 int err; 997 int err;
472 struct p9_fcall *tc, *rc;
473 struct p9_client *clnt; 998 struct p9_client *clnt;
999 struct p9_req_t *req;
1000 struct p9_qid qid;
1001 int iounit;
474 1002
475 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid, 1003 P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n",
476 name, perm, mode); 1004 fid->fid, name, perm, mode);
477 err = 0; 1005 err = 0;
478 tc = NULL;
479 rc = NULL;
480 clnt = fid->clnt; 1006 clnt = fid->clnt;
481 1007
482 if (fid->mode != -1) 1008 if (fid->mode != -1)
483 return -EINVAL; 1009 return -EINVAL;
484 1010
485 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension, 1011 req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm,
486 clnt->dotu); 1012 mode, extension);
487 if (IS_ERR(tc)) { 1013 if (IS_ERR(req)) {
488 err = PTR_ERR(tc); 1014 err = PTR_ERR(req);
489 tc = NULL; 1015 goto error;
490 goto done;
491 } 1016 }
492 1017
493 err = p9_client_rpc(clnt, tc, &rc); 1018 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit);
494 if (err) 1019 if (err) {
495 goto done; 1020 p9pdu_dump(1, req->rc);
1021 goto free_and_error;
1022 }
1023
1024 P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n",
1025 qid.type, qid.path, qid.version, iounit);
496 1026
497 fid->mode = mode; 1027 fid->mode = mode;
498 fid->iounit = rc->params.ropen.iounit; 1028 fid->iounit = iounit;
499 1029
500done: 1030free_and_error:
501 kfree(tc); 1031 p9_free_req(clnt, req);
502 kfree(rc); 1032error:
503 return err; 1033 return err;
504} 1034}
505EXPORT_SYMBOL(p9_client_fcreate); 1035EXPORT_SYMBOL(p9_client_fcreate);
@@ -507,31 +1037,25 @@ EXPORT_SYMBOL(p9_client_fcreate);
507int p9_client_clunk(struct p9_fid *fid) 1037int p9_client_clunk(struct p9_fid *fid)
508{ 1038{
509 int err; 1039 int err;
510 struct p9_fcall *tc, *rc;
511 struct p9_client *clnt; 1040 struct p9_client *clnt;
1041 struct p9_req_t *req;
512 1042
513 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 1043 P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
514 err = 0; 1044 err = 0;
515 tc = NULL;
516 rc = NULL;
517 clnt = fid->clnt; 1045 clnt = fid->clnt;
518 1046
519 tc = p9_create_tclunk(fid->fid); 1047 req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid);
520 if (IS_ERR(tc)) { 1048 if (IS_ERR(req)) {
521 err = PTR_ERR(tc); 1049 err = PTR_ERR(req);
522 tc = NULL; 1050 goto error;
523 goto done;
524 } 1051 }
525 1052
526 err = p9_client_rpc(clnt, tc, &rc); 1053 P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
527 if (err)
528 goto done;
529 1054
1055 p9_free_req(clnt, req);
530 p9_fid_destroy(fid); 1056 p9_fid_destroy(fid);
531 1057
532done: 1058error:
533 kfree(tc);
534 kfree(rc);
535 return err; 1059 return err;
536} 1060}
537EXPORT_SYMBOL(p9_client_clunk); 1061EXPORT_SYMBOL(p9_client_clunk);
@@ -539,157 +1063,41 @@ EXPORT_SYMBOL(p9_client_clunk);
539int p9_client_remove(struct p9_fid *fid) 1063int p9_client_remove(struct p9_fid *fid)
540{ 1064{
541 int err; 1065 int err;
542 struct p9_fcall *tc, *rc;
543 struct p9_client *clnt; 1066 struct p9_client *clnt;
1067 struct p9_req_t *req;
544 1068
545 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 1069 P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid);
546 err = 0; 1070 err = 0;
547 tc = NULL;
548 rc = NULL;
549 clnt = fid->clnt; 1071 clnt = fid->clnt;
550 1072
551 tc = p9_create_tremove(fid->fid); 1073 req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid);
552 if (IS_ERR(tc)) { 1074 if (IS_ERR(req)) {
553 err = PTR_ERR(tc); 1075 err = PTR_ERR(req);
554 tc = NULL; 1076 goto error;
555 goto done;
556 } 1077 }
557 1078
558 err = p9_client_rpc(clnt, tc, &rc); 1079 P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
559 if (err)
560 goto done;
561 1080
1081 p9_free_req(clnt, req);
562 p9_fid_destroy(fid); 1082 p9_fid_destroy(fid);
563 1083
564done:
565 kfree(tc);
566 kfree(rc);
567 return err;
568}
569EXPORT_SYMBOL(p9_client_remove);
570
571int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
572{
573 int err, n, rsize, total;
574 struct p9_fcall *tc, *rc;
575 struct p9_client *clnt;
576
577 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
578 (long long unsigned) offset, count);
579 err = 0;
580 tc = NULL;
581 rc = NULL;
582 clnt = fid->clnt;
583 total = 0;
584
585 rsize = fid->iounit;
586 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
587 rsize = clnt->msize - P9_IOHDRSZ;
588
589 do {
590 if (count < rsize)
591 rsize = count;
592
593 tc = p9_create_tread(fid->fid, offset, rsize);
594 if (IS_ERR(tc)) {
595 err = PTR_ERR(tc);
596 tc = NULL;
597 goto error;
598 }
599
600 err = p9_client_rpc(clnt, tc, &rc);
601 if (err)
602 goto error;
603
604 n = rc->params.rread.count;
605 if (n > count)
606 n = count;
607
608 memmove(data, rc->params.rread.data, n);
609 count -= n;
610 data += n;
611 offset += n;
612 total += n;
613 kfree(tc);
614 tc = NULL;
615 kfree(rc);
616 rc = NULL;
617 } while (count > 0 && n == rsize);
618
619 return total;
620
621error: 1084error:
622 kfree(tc);
623 kfree(rc);
624 return err; 1085 return err;
625} 1086}
626EXPORT_SYMBOL(p9_client_read); 1087EXPORT_SYMBOL(p9_client_remove);
627
628int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
629{
630 int err, n, rsize, total;
631 struct p9_fcall *tc, *rc;
632 struct p9_client *clnt;
633
634 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
635 (long long unsigned) offset, count);
636 err = 0;
637 tc = NULL;
638 rc = NULL;
639 clnt = fid->clnt;
640 total = 0;
641
642 rsize = fid->iounit;
643 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
644 rsize = clnt->msize - P9_IOHDRSZ;
645
646 do {
647 if (count < rsize)
648 rsize = count;
649
650 tc = p9_create_twrite(fid->fid, offset, rsize, data);
651 if (IS_ERR(tc)) {
652 err = PTR_ERR(tc);
653 tc = NULL;
654 goto error;
655 }
656
657 err = p9_client_rpc(clnt, tc, &rc);
658 if (err)
659 goto error;
660
661 n = rc->params.rread.count;
662 count -= n;
663 data += n;
664 offset += n;
665 total += n;
666 kfree(tc);
667 tc = NULL;
668 kfree(rc);
669 rc = NULL;
670 } while (count > 0);
671
672 return total;
673
674error:
675 kfree(tc);
676 kfree(rc);
677 return err;
678}
679EXPORT_SYMBOL(p9_client_write);
680 1088
681int 1089int
682p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count) 1090p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
1091 u32 count)
683{ 1092{
684 int err, n, rsize, total; 1093 int err, rsize, total;
685 struct p9_fcall *tc, *rc;
686 struct p9_client *clnt; 1094 struct p9_client *clnt;
1095 struct p9_req_t *req;
1096 char *dataptr;
687 1097
688 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 1098 P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid,
689 (long long unsigned) offset, count); 1099 (long long unsigned) offset, count);
690 err = 0; 1100 err = 0;
691 tc = NULL;
692 rc = NULL;
693 clnt = fid->clnt; 1101 clnt = fid->clnt;
694 total = 0; 1102 total = 0;
695 1103
@@ -697,63 +1105,57 @@ p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
697 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 1105 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
698 rsize = clnt->msize - P9_IOHDRSZ; 1106 rsize = clnt->msize - P9_IOHDRSZ;
699 1107
700 do { 1108 if (count < rsize)
701 if (count < rsize) 1109 rsize = count;
702 rsize = count;
703 1110
704 tc = p9_create_tread(fid->fid, offset, rsize); 1111 req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize);
705 if (IS_ERR(tc)) { 1112 if (IS_ERR(req)) {
706 err = PTR_ERR(tc); 1113 err = PTR_ERR(req);
707 tc = NULL; 1114 goto error;
708 goto error; 1115 }
709 }
710 1116
711 err = p9_client_rpc(clnt, tc, &rc); 1117 err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr);
712 if (err) 1118 if (err) {
713 goto error; 1119 p9pdu_dump(1, req->rc);
1120 goto free_and_error;
1121 }
1122
1123 P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
714 1124
715 n = rc->params.rread.count; 1125 if (data) {
716 if (n > count) 1126 memmove(data, dataptr, count);
717 n = count; 1127 data += count;
1128 }
718 1129
719 err = copy_to_user(data, rc->params.rread.data, n); 1130 if (udata) {
1131 err = copy_to_user(udata, dataptr, count);
720 if (err) { 1132 if (err) {
721 err = -EFAULT; 1133 err = -EFAULT;
722 goto error; 1134 goto free_and_error;
723 } 1135 }
1136 }
724 1137
725 count -= n; 1138 p9_free_req(clnt, req);
726 data += n; 1139 return count;
727 offset += n;
728 total += n;
729 kfree(tc);
730 tc = NULL;
731 kfree(rc);
732 rc = NULL;
733 } while (count > 0 && n == rsize);
734
735 return total;
736 1140
1141free_and_error:
1142 p9_free_req(clnt, req);
737error: 1143error:
738 kfree(tc);
739 kfree(rc);
740 return err; 1144 return err;
741} 1145}
742EXPORT_SYMBOL(p9_client_uread); 1146EXPORT_SYMBOL(p9_client_read);
743 1147
744int 1148int
745p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset, 1149p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
746 u32 count) 1150 u64 offset, u32 count)
747{ 1151{
748 int err, n, rsize, total; 1152 int err, rsize, total;
749 struct p9_fcall *tc, *rc;
750 struct p9_client *clnt; 1153 struct p9_client *clnt;
1154 struct p9_req_t *req;
751 1155
752 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 1156 P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n",
753 (long long unsigned) offset, count); 1157 fid->fid, (long long unsigned) offset, count);
754 err = 0; 1158 err = 0;
755 tc = NULL;
756 rc = NULL;
757 clnt = fid->clnt; 1159 clnt = fid->clnt;
758 total = 0; 1160 total = 0;
759 1161
@@ -761,325 +1163,114 @@ p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
761 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 1163 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
762 rsize = clnt->msize - P9_IOHDRSZ; 1164 rsize = clnt->msize - P9_IOHDRSZ;
763 1165
764 do { 1166 if (count < rsize)
765 if (count < rsize) 1167 rsize = count;
766 rsize = count; 1168 if (data)
767 1169 req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset,
768 tc = p9_create_twrite_u(fid->fid, offset, rsize, data); 1170 rsize, data);
769 if (IS_ERR(tc)) { 1171 else
770 err = PTR_ERR(tc); 1172 req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset,
771 tc = NULL; 1173 rsize, udata);
772 goto error; 1174 if (IS_ERR(req)) {
773 } 1175 err = PTR_ERR(req);
1176 goto error;
1177 }
774 1178
775 err = p9_client_rpc(clnt, tc, &rc); 1179 err = p9pdu_readf(req->rc, clnt->dotu, "d", &count);
776 if (err) 1180 if (err) {
777 goto error; 1181 p9pdu_dump(1, req->rc);
1182 goto free_and_error;
1183 }
778 1184
779 n = rc->params.rread.count; 1185 P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
780 count -= n;
781 data += n;
782 offset += n;
783 total += n;
784 kfree(tc);
785 tc = NULL;
786 kfree(rc);
787 rc = NULL;
788 } while (count > 0);
789 1186
790 return total; 1187 p9_free_req(clnt, req);
1188 return count;
791 1189
1190free_and_error:
1191 p9_free_req(clnt, req);
792error: 1192error:
793 kfree(tc);
794 kfree(rc);
795 return err; 1193 return err;
796} 1194}
797EXPORT_SYMBOL(p9_client_uwrite); 1195EXPORT_SYMBOL(p9_client_write);
798
799int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
800{
801 int n, total;
802
803 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
804 (long long unsigned) offset, count);
805 n = 0;
806 total = 0;
807 while (count) {
808 n = p9_client_read(fid, data, offset, count);
809 if (n <= 0)
810 break;
811
812 data += n;
813 offset += n;
814 count -= n;
815 total += n;
816 }
817
818 if (n < 0)
819 total = n;
820
821 return total;
822}
823EXPORT_SYMBOL(p9_client_readn);
824 1196
825struct p9_stat *p9_client_stat(struct p9_fid *fid) 1197struct p9_wstat *p9_client_stat(struct p9_fid *fid)
826{ 1198{
827 int err; 1199 int err;
828 struct p9_fcall *tc, *rc;
829 struct p9_client *clnt; 1200 struct p9_client *clnt;
830 struct p9_stat *ret; 1201 struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL);
1202 struct p9_req_t *req;
1203 u16 ignored;
1204
1205 P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid);
1206
1207 if (!ret)
1208 return ERR_PTR(-ENOMEM);
831 1209
832 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
833 err = 0; 1210 err = 0;
834 tc = NULL;
835 rc = NULL;
836 ret = NULL;
837 clnt = fid->clnt; 1211 clnt = fid->clnt;
838 1212
839 tc = p9_create_tstat(fid->fid); 1213 req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid);
840 if (IS_ERR(tc)) { 1214 if (IS_ERR(req)) {
841 err = PTR_ERR(tc); 1215 err = PTR_ERR(req);
842 tc = NULL;
843 goto error; 1216 goto error;
844 } 1217 }
845 1218
846 err = p9_client_rpc(clnt, tc, &rc); 1219 err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret);
847 if (err) 1220 if (err) {
848 goto error; 1221 ret = ERR_PTR(err);
849 1222 p9pdu_dump(1, req->rc);
850 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu); 1223 goto free_and_error;
851 if (IS_ERR(ret)) {
852 err = PTR_ERR(ret);
853 ret = NULL;
854 goto error;
855 } 1224 }
856 1225
857 kfree(tc); 1226 P9_DPRINTK(P9_DEBUG_9P,
858 kfree(rc); 1227 "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
859 return ret; 1228 "<<< mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
860 1229 "<<< name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
1230 "<<< uid=%d gid=%d n_muid=%d\n",
1231 ret->size, ret->type, ret->dev, ret->qid.type,
1232 ret->qid.path, ret->qid.version, ret->mode,
1233 ret->atime, ret->mtime, ret->length, ret->name,
1234 ret->uid, ret->gid, ret->muid, ret->extension,
1235 ret->n_uid, ret->n_gid, ret->n_muid);
1236
1237free_and_error:
1238 p9_free_req(clnt, req);
861error: 1239error:
862 kfree(tc); 1240 return ret;
863 kfree(rc);
864 kfree(ret);
865 return ERR_PTR(err);
866} 1241}
867EXPORT_SYMBOL(p9_client_stat); 1242EXPORT_SYMBOL(p9_client_stat);
868 1243
869int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) 1244int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
870{ 1245{
871 int err; 1246 int err;
872 struct p9_fcall *tc, *rc; 1247 struct p9_req_t *req;
873 struct p9_client *clnt; 1248 struct p9_client *clnt;
874 1249
875 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 1250 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
1251 P9_DPRINTK(P9_DEBUG_9P,
1252 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
1253 " mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
1254 " name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
1255 " uid=%d gid=%d n_muid=%d\n",
1256 wst->size, wst->type, wst->dev, wst->qid.type,
1257 wst->qid.path, wst->qid.version, wst->mode,
1258 wst->atime, wst->mtime, wst->length, wst->name,
1259 wst->uid, wst->gid, wst->muid, wst->extension,
1260 wst->n_uid, wst->n_gid, wst->n_muid);
876 err = 0; 1261 err = 0;
877 tc = NULL;
878 rc = NULL;
879 clnt = fid->clnt; 1262 clnt = fid->clnt;
880 1263
881 tc = p9_create_twstat(fid->fid, wst, clnt->dotu); 1264 req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, 0, wst);
882 if (IS_ERR(tc)) { 1265 if (IS_ERR(req)) {
883 err = PTR_ERR(tc); 1266 err = PTR_ERR(req);
884 tc = NULL;
885 goto done;
886 }
887
888 err = p9_client_rpc(clnt, tc, &rc);
889
890done:
891 kfree(tc);
892 kfree(rc);
893 return err;
894}
895EXPORT_SYMBOL(p9_client_wstat);
896
897struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
898{
899 int err, n, m;
900 struct p9_fcall *tc, *rc;
901 struct p9_client *clnt;
902 struct p9_stat st, *ret;
903
904 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
905 (long long unsigned) offset);
906 err = 0;
907 tc = NULL;
908 rc = NULL;
909 ret = NULL;
910 clnt = fid->clnt;
911
912 /* if the offset is below or above the current response, free it */
913 if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
914 offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
915 fid->rdir_pos = 0;
916 if (fid->rdir_fcall)
917 fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
918
919 kfree(fid->rdir_fcall);
920 fid->rdir_fcall = NULL;
921 if (offset < fid->rdir_fpos)
922 fid->rdir_fpos = 0;
923 }
924
925 if (!fid->rdir_fcall) {
926 n = fid->iounit;
927 if (!n || n > clnt->msize-P9_IOHDRSZ)
928 n = clnt->msize - P9_IOHDRSZ;
929
930 while (1) {
931 if (fid->rdir_fcall) {
932 fid->rdir_fpos +=
933 fid->rdir_fcall->params.rread.count;
934 kfree(fid->rdir_fcall);
935 fid->rdir_fcall = NULL;
936 }
937
938 tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
939 if (IS_ERR(tc)) {
940 err = PTR_ERR(tc);
941 tc = NULL;
942 goto error;
943 }
944
945 err = p9_client_rpc(clnt, tc, &rc);
946 if (err)
947 goto error;
948
949 n = rc->params.rread.count;
950 if (n == 0)
951 goto done;
952
953 fid->rdir_fcall = rc;
954 rc = NULL;
955 if (offset >= fid->rdir_fpos &&
956 offset < fid->rdir_fpos+n)
957 break;
958 }
959
960 fid->rdir_pos = 0;
961 }
962
963 m = offset - fid->rdir_fpos;
964 if (m < 0)
965 goto done;
966
967 n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
968 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
969
970 if (!n) {
971 err = -EIO;
972 goto error;
973 }
974
975 fid->rdir_pos += n;
976 st.size = n;
977 ret = p9_clone_stat(&st, clnt->dotu);
978 if (IS_ERR(ret)) {
979 err = PTR_ERR(ret);
980 ret = NULL;
981 goto error;
982 }
983
984done:
985 kfree(tc);
986 kfree(rc);
987 return ret;
988
989error:
990 kfree(tc);
991 kfree(rc);
992 kfree(ret);
993 return ERR_PTR(err);
994}
995EXPORT_SYMBOL(p9_client_dirread);
996
997static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
998{
999 int n;
1000 char *p;
1001 struct p9_stat *ret;
1002
1003 n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
1004 st->muid.len;
1005
1006 if (dotu)
1007 n += st->extension.len;
1008
1009 ret = kmalloc(n, GFP_KERNEL);
1010 if (!ret)
1011 return ERR_PTR(-ENOMEM);
1012
1013 memmove(ret, st, sizeof(struct p9_stat));
1014 p = ((char *) ret) + sizeof(struct p9_stat);
1015 memmove(p, st->name.str, st->name.len);
1016 ret->name.str = p;
1017 p += st->name.len;
1018 memmove(p, st->uid.str, st->uid.len);
1019 ret->uid.str = p;
1020 p += st->uid.len;
1021 memmove(p, st->gid.str, st->gid.len);
1022 ret->gid.str = p;
1023 p += st->gid.len;
1024 memmove(p, st->muid.str, st->muid.len);
1025 ret->muid.str = p;
1026 p += st->muid.len;
1027
1028 if (dotu) {
1029 memmove(p, st->extension.str, st->extension.len);
1030 ret->extension.str = p;
1031 p += st->extension.len;
1032 }
1033
1034 return ret;
1035}
1036
1037static struct p9_fid *p9_fid_create(struct p9_client *clnt)
1038{
1039 int err;
1040 struct p9_fid *fid;
1041
1042 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
1043 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
1044 if (!fid)
1045 return ERR_PTR(-ENOMEM);
1046
1047 fid->fid = p9_idpool_get(clnt->fidpool);
1048 if (fid->fid < 0) {
1049 err = -ENOSPC;
1050 goto error; 1267 goto error;
1051 } 1268 }
1052 1269
1053 memset(&fid->qid, 0, sizeof(struct p9_qid)); 1270 P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid);
1054 fid->mode = -1;
1055 fid->rdir_fpos = 0;
1056 fid->rdir_pos = 0;
1057 fid->rdir_fcall = NULL;
1058 fid->uid = current->fsuid;
1059 fid->clnt = clnt;
1060 fid->aux = NULL;
1061
1062 spin_lock(&clnt->lock);
1063 list_add(&fid->flist, &clnt->fidlist);
1064 spin_unlock(&clnt->lock);
1065
1066 return fid;
1067 1271
1272 p9_free_req(clnt, req);
1068error: 1273error:
1069 kfree(fid); 1274 return err;
1070 return ERR_PTR(err);
1071}
1072
1073static void p9_fid_destroy(struct p9_fid *fid)
1074{
1075 struct p9_client *clnt;
1076
1077 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
1078 clnt = fid->clnt;
1079 p9_idpool_put(fid->fid, clnt->fidpool);
1080 spin_lock(&clnt->lock);
1081 list_del(&fid->flist);
1082 spin_unlock(&clnt->lock);
1083 kfree(fid->rdir_fcall);
1084 kfree(fid);
1085} 1275}
1276EXPORT_SYMBOL(p9_client_wstat);
diff --git a/net/9p/conv.c b/net/9p/conv.c
deleted file mode 100644
index 5ad3a3bd73b2..000000000000
--- a/net/9p/conv.c
+++ /dev/null
@@ -1,1054 +0,0 @@
1/*
2 * net/9p/conv.c
3 *
4 * 9P protocol conversion functions
5 *
6 * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/fs.h>
30#include <linux/sched.h>
31#include <linux/idr.h>
32#include <linux/uaccess.h>
33#include <net/9p/9p.h>
34
35/*
36 * Buffer to help with string parsing
37 */
38struct cbuf {
39 unsigned char *sp;
40 unsigned char *p;
41 unsigned char *ep;
42};
43
44static inline void buf_init(struct cbuf *buf, void *data, int datalen)
45{
46 buf->sp = buf->p = data;
47 buf->ep = data + datalen;
48}
49
50static inline int buf_check_overflow(struct cbuf *buf)
51{
52 return buf->p > buf->ep;
53}
54
55static int buf_check_size(struct cbuf *buf, int len)
56{
57 if (buf->p + len > buf->ep) {
58 if (buf->p < buf->ep) {
59 P9_EPRINTK(KERN_ERR,
60 "buffer overflow: want %d has %d\n", len,
61 (int)(buf->ep - buf->p));
62 dump_stack();
63 buf->p = buf->ep + 1;
64 }
65
66 return 0;
67 }
68
69 return 1;
70}
71
72static void *buf_alloc(struct cbuf *buf, int len)
73{
74 void *ret = NULL;
75
76 if (buf_check_size(buf, len)) {
77 ret = buf->p;
78 buf->p += len;
79 }
80
81 return ret;
82}
83
84static void buf_put_int8(struct cbuf *buf, u8 val)
85{
86 if (buf_check_size(buf, 1)) {
87 buf->p[0] = val;
88 buf->p++;
89 }
90}
91
92static void buf_put_int16(struct cbuf *buf, u16 val)
93{
94 if (buf_check_size(buf, 2)) {
95 *(__le16 *) buf->p = cpu_to_le16(val);
96 buf->p += 2;
97 }
98}
99
100static void buf_put_int32(struct cbuf *buf, u32 val)
101{
102 if (buf_check_size(buf, 4)) {
103 *(__le32 *)buf->p = cpu_to_le32(val);
104 buf->p += 4;
105 }
106}
107
108static void buf_put_int64(struct cbuf *buf, u64 val)
109{
110 if (buf_check_size(buf, 8)) {
111 *(__le64 *)buf->p = cpu_to_le64(val);
112 buf->p += 8;
113 }
114}
115
116static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
117{
118 char *ret;
119
120 ret = NULL;
121 if (buf_check_size(buf, slen + 2)) {
122 buf_put_int16(buf, slen);
123 ret = buf->p;
124 memcpy(buf->p, s, slen);
125 buf->p += slen;
126 }
127
128 return ret;
129}
130
131static u8 buf_get_int8(struct cbuf *buf)
132{
133 u8 ret = 0;
134
135 if (buf_check_size(buf, 1)) {
136 ret = buf->p[0];
137 buf->p++;
138 }
139
140 return ret;
141}
142
143static u16 buf_get_int16(struct cbuf *buf)
144{
145 u16 ret = 0;
146
147 if (buf_check_size(buf, 2)) {
148 ret = le16_to_cpu(*(__le16 *)buf->p);
149 buf->p += 2;
150 }
151
152 return ret;
153}
154
155static u32 buf_get_int32(struct cbuf *buf)
156{
157 u32 ret = 0;
158
159 if (buf_check_size(buf, 4)) {
160 ret = le32_to_cpu(*(__le32 *)buf->p);
161 buf->p += 4;
162 }
163
164 return ret;
165}
166
167static u64 buf_get_int64(struct cbuf *buf)
168{
169 u64 ret = 0;
170
171 if (buf_check_size(buf, 8)) {
172 ret = le64_to_cpu(*(__le64 *)buf->p);
173 buf->p += 8;
174 }
175
176 return ret;
177}
178
179static void buf_get_str(struct cbuf *buf, struct p9_str *vstr)
180{
181 vstr->len = buf_get_int16(buf);
182 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
183 vstr->str = buf->p;
184 buf->p += vstr->len;
185 } else {
186 vstr->len = 0;
187 vstr->str = NULL;
188 }
189}
190
191static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid)
192{
193 qid->type = buf_get_int8(bufp);
194 qid->version = buf_get_int32(bufp);
195 qid->path = buf_get_int64(bufp);
196}
197
198/**
199 * p9_size_wstat - calculate the size of a variable length stat struct
200 * @wstat: metadata (stat) structure
201 * @dotu: non-zero if 9P2000.u
202 *
203 */
204
205static int p9_size_wstat(struct p9_wstat *wstat, int dotu)
206{
207 int size = 0;
208
209 if (wstat == NULL) {
210 P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n");
211 return 0;
212 }
213
214 size = /* 2 + *//* size[2] */
215 2 + /* type[2] */
216 4 + /* dev[4] */
217 1 + /* qid.type[1] */
218 4 + /* qid.vers[4] */
219 8 + /* qid.path[8] */
220 4 + /* mode[4] */
221 4 + /* atime[4] */
222 4 + /* mtime[4] */
223 8 + /* length[8] */
224 8; /* minimum sum of string lengths */
225
226 if (wstat->name)
227 size += strlen(wstat->name);
228 if (wstat->uid)
229 size += strlen(wstat->uid);
230 if (wstat->gid)
231 size += strlen(wstat->gid);
232 if (wstat->muid)
233 size += strlen(wstat->muid);
234
235 if (dotu) {
236 size += 4 + /* n_uid[4] */
237 4 + /* n_gid[4] */
238 4 + /* n_muid[4] */
239 2; /* string length of extension[4] */
240 if (wstat->extension)
241 size += strlen(wstat->extension);
242 }
243
244 return size;
245}
246
247/**
248 * buf_get_stat - safely decode a recieved metadata (stat) structure
249 * @bufp: buffer to deserialize
250 * @stat: metadata (stat) structure
251 * @dotu: non-zero if 9P2000.u
252 *
253 */
254
255static void
256buf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu)
257{
258 stat->size = buf_get_int16(bufp);
259 stat->type = buf_get_int16(bufp);
260 stat->dev = buf_get_int32(bufp);
261 stat->qid.type = buf_get_int8(bufp);
262 stat->qid.version = buf_get_int32(bufp);
263 stat->qid.path = buf_get_int64(bufp);
264 stat->mode = buf_get_int32(bufp);
265 stat->atime = buf_get_int32(bufp);
266 stat->mtime = buf_get_int32(bufp);
267 stat->length = buf_get_int64(bufp);
268 buf_get_str(bufp, &stat->name);
269 buf_get_str(bufp, &stat->uid);
270 buf_get_str(bufp, &stat->gid);
271 buf_get_str(bufp, &stat->muid);
272
273 if (dotu) {
274 buf_get_str(bufp, &stat->extension);
275 stat->n_uid = buf_get_int32(bufp);
276 stat->n_gid = buf_get_int32(bufp);
277 stat->n_muid = buf_get_int32(bufp);
278 }
279}
280
281/**
282 * p9_deserialize_stat - decode a received metadata structure
283 * @buf: buffer to deserialize
284 * @buflen: length of received buffer
285 * @stat: metadata structure to decode into
286 * @dotu: non-zero if 9P2000.u
287 *
288 * Note: stat will point to the buf region.
289 */
290
291int
292p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat,
293 int dotu)
294{
295 struct cbuf buffer;
296 struct cbuf *bufp = &buffer;
297 unsigned char *p;
298
299 buf_init(bufp, buf, buflen);
300 p = bufp->p;
301 buf_get_stat(bufp, stat, dotu);
302
303 if (buf_check_overflow(bufp))
304 return 0;
305 else
306 return bufp->p - p;
307}
308EXPORT_SYMBOL(p9_deserialize_stat);
309
310/**
311 * deserialize_fcall - unmarshal a response
312 * @buf: recieved buffer
313 * @buflen: length of received buffer
314 * @rcall: fcall structure to populate
315 * @rcalllen: length of fcall structure to populate
316 * @dotu: non-zero if 9P2000.u
317 *
318 */
319
320int
321p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall,
322 int dotu)
323{
324
325 struct cbuf buffer;
326 struct cbuf *bufp = &buffer;
327 int i = 0;
328
329 buf_init(bufp, buf, buflen);
330
331 rcall->size = buf_get_int32(bufp);
332 rcall->id = buf_get_int8(bufp);
333 rcall->tag = buf_get_int16(bufp);
334
335 P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size,
336 rcall->id, rcall->tag);
337
338 switch (rcall->id) {
339 default:
340 P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id);
341 return -EPROTO;
342 case P9_RVERSION:
343 rcall->params.rversion.msize = buf_get_int32(bufp);
344 buf_get_str(bufp, &rcall->params.rversion.version);
345 break;
346 case P9_RFLUSH:
347 break;
348 case P9_RATTACH:
349 rcall->params.rattach.qid.type = buf_get_int8(bufp);
350 rcall->params.rattach.qid.version = buf_get_int32(bufp);
351 rcall->params.rattach.qid.path = buf_get_int64(bufp);
352 break;
353 case P9_RWALK:
354 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
355 if (rcall->params.rwalk.nwqid > P9_MAXWELEM) {
356 P9_EPRINTK(KERN_ERR,
357 "Rwalk with more than %d qids: %d\n",
358 P9_MAXWELEM, rcall->params.rwalk.nwqid);
359 return -EPROTO;
360 }
361
362 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
363 buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
364 break;
365 case P9_ROPEN:
366 buf_get_qid(bufp, &rcall->params.ropen.qid);
367 rcall->params.ropen.iounit = buf_get_int32(bufp);
368 break;
369 case P9_RCREATE:
370 buf_get_qid(bufp, &rcall->params.rcreate.qid);
371 rcall->params.rcreate.iounit = buf_get_int32(bufp);
372 break;
373 case P9_RREAD:
374 rcall->params.rread.count = buf_get_int32(bufp);
375 rcall->params.rread.data = bufp->p;
376 buf_check_size(bufp, rcall->params.rread.count);
377 break;
378 case P9_RWRITE:
379 rcall->params.rwrite.count = buf_get_int32(bufp);
380 break;
381 case P9_RCLUNK:
382 break;
383 case P9_RREMOVE:
384 break;
385 case P9_RSTAT:
386 buf_get_int16(bufp);
387 buf_get_stat(bufp, &rcall->params.rstat.stat, dotu);
388 break;
389 case P9_RWSTAT:
390 break;
391 case P9_RERROR:
392 buf_get_str(bufp, &rcall->params.rerror.error);
393 if (dotu)
394 rcall->params.rerror.errno = buf_get_int16(bufp);
395 break;
396 }
397
398 if (buf_check_overflow(bufp)) {
399 P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n");
400 return -EIO;
401 }
402
403 return bufp->p - bufp->sp;
404}
405EXPORT_SYMBOL(p9_deserialize_fcall);
406
407static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p)
408{
409 *p = val;
410 buf_put_int8(bufp, val);
411}
412
413static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p)
414{
415 *p = val;
416 buf_put_int16(bufp, val);
417}
418
419static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p)
420{
421 *p = val;
422 buf_put_int32(bufp, val);
423}
424
425static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p)
426{
427 *p = val;
428 buf_put_int64(bufp, val);
429}
430
431static void
432p9_put_str(struct cbuf *bufp, char *data, struct p9_str *str)
433{
434 int len;
435 char *s;
436
437 if (data)
438 len = strlen(data);
439 else
440 len = 0;
441
442 s = buf_put_stringn(bufp, data, len);
443 if (str) {
444 str->len = len;
445 str->str = s;
446 }
447}
448
449static int
450p9_put_data(struct cbuf *bufp, const char *data, int count,
451 unsigned char **pdata)
452{
453 *pdata = buf_alloc(bufp, count);
454 if (*pdata == NULL)
455 return -ENOMEM;
456 memmove(*pdata, data, count);
457 return 0;
458}
459
460static int
461p9_put_user_data(struct cbuf *bufp, const char __user *data, int count,
462 unsigned char **pdata)
463{
464 *pdata = buf_alloc(bufp, count);
465 if (*pdata == NULL)
466 return -ENOMEM;
467 return copy_from_user(*pdata, data, count);
468}
469
470static void
471p9_put_wstat(struct cbuf *bufp, struct p9_wstat *wstat,
472 struct p9_stat *stat, int statsz, int dotu)
473{
474 p9_put_int16(bufp, statsz, &stat->size);
475 p9_put_int16(bufp, wstat->type, &stat->type);
476 p9_put_int32(bufp, wstat->dev, &stat->dev);
477 p9_put_int8(bufp, wstat->qid.type, &stat->qid.type);
478 p9_put_int32(bufp, wstat->qid.version, &stat->qid.version);
479 p9_put_int64(bufp, wstat->qid.path, &stat->qid.path);
480 p9_put_int32(bufp, wstat->mode, &stat->mode);
481 p9_put_int32(bufp, wstat->atime, &stat->atime);
482 p9_put_int32(bufp, wstat->mtime, &stat->mtime);
483 p9_put_int64(bufp, wstat->length, &stat->length);
484
485 p9_put_str(bufp, wstat->name, &stat->name);
486 p9_put_str(bufp, wstat->uid, &stat->uid);
487 p9_put_str(bufp, wstat->gid, &stat->gid);
488 p9_put_str(bufp, wstat->muid, &stat->muid);
489
490 if (dotu) {
491 p9_put_str(bufp, wstat->extension, &stat->extension);
492 p9_put_int32(bufp, wstat->n_uid, &stat->n_uid);
493 p9_put_int32(bufp, wstat->n_gid, &stat->n_gid);
494 p9_put_int32(bufp, wstat->n_muid, &stat->n_muid);
495 }
496}
497
498static struct p9_fcall *
499p9_create_common(struct cbuf *bufp, u32 size, u8 id)
500{
501 struct p9_fcall *fc;
502
503 size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
504 fc = kmalloc(sizeof(struct p9_fcall) + size, GFP_KERNEL);
505 if (!fc)
506 return ERR_PTR(-ENOMEM);
507
508 fc->sdata = (char *)fc + sizeof(*fc);
509
510 buf_init(bufp, (char *)fc->sdata, size);
511 p9_put_int32(bufp, size, &fc->size);
512 p9_put_int8(bufp, id, &fc->id);
513 p9_put_int16(bufp, P9_NOTAG, &fc->tag);
514
515 return fc;
516}
517
518/**
519 * p9_set_tag - set the tag field of an &p9_fcall structure
520 * @fc: fcall structure to set tag within
521 * @tag: tag id to set
522 */
523
524void p9_set_tag(struct p9_fcall *fc, u16 tag)
525{
526 fc->tag = tag;
527 *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
528}
529EXPORT_SYMBOL(p9_set_tag);
530
531/**
532 * p9_create_tversion - allocates and creates a T_VERSION request
533 * @msize: requested maximum data size
534 * @version: version string to negotiate
535 *
536 */
537struct p9_fcall *p9_create_tversion(u32 msize, char *version)
538{
539 int size;
540 struct p9_fcall *fc;
541 struct cbuf buffer;
542 struct cbuf *bufp = &buffer;
543
544 size = 4 + 2 + strlen(version); /* msize[4] version[s] */
545 fc = p9_create_common(bufp, size, P9_TVERSION);
546 if (IS_ERR(fc))
547 goto error;
548
549 p9_put_int32(bufp, msize, &fc->params.tversion.msize);
550 p9_put_str(bufp, version, &fc->params.tversion.version);
551
552 if (buf_check_overflow(bufp)) {
553 kfree(fc);
554 fc = ERR_PTR(-ENOMEM);
555 }
556error:
557 return fc;
558}
559EXPORT_SYMBOL(p9_create_tversion);
560
561/**
562 * p9_create_tauth - allocates and creates a T_AUTH request
563 * @afid: handle to use for authentication protocol
564 * @uname: user name attempting to authenticate
565 * @aname: mount specifier for remote server
566 * @n_uname: numeric id for user attempting to authneticate
567 * @dotu: 9P2000.u extension flag
568 *
569 */
570
571struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname,
572 u32 n_uname, int dotu)
573{
574 int size;
575 struct p9_fcall *fc;
576 struct cbuf buffer;
577 struct cbuf *bufp = &buffer;
578
579 /* afid[4] uname[s] aname[s] */
580 size = 4 + 2 + 2;
581 if (uname)
582 size += strlen(uname);
583
584 if (aname)
585 size += strlen(aname);
586
587 if (dotu)
588 size += 4; /* n_uname */
589
590 fc = p9_create_common(bufp, size, P9_TAUTH);
591 if (IS_ERR(fc))
592 goto error;
593
594 p9_put_int32(bufp, afid, &fc->params.tauth.afid);
595 p9_put_str(bufp, uname, &fc->params.tauth.uname);
596 p9_put_str(bufp, aname, &fc->params.tauth.aname);
597 if (dotu)
598 p9_put_int32(bufp, n_uname, &fc->params.tauth.n_uname);
599
600 if (buf_check_overflow(bufp)) {
601 kfree(fc);
602 fc = ERR_PTR(-ENOMEM);
603 }
604error:
605 return fc;
606}
607EXPORT_SYMBOL(p9_create_tauth);
608
609/**
610 * p9_create_tattach - allocates and creates a T_ATTACH request
611 * @fid: handle to use for the new mount point
612 * @afid: handle to use for authentication protocol
613 * @uname: user name attempting to attach
614 * @aname: mount specifier for remote server
615 * @n_uname: numeric id for user attempting to attach
616 * @n_uname: numeric id for user attempting to attach
617 * @dotu: 9P2000.u extension flag
618 *
619 */
620
621struct p9_fcall *
622p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname,
623 u32 n_uname, int dotu)
624{
625 int size;
626 struct p9_fcall *fc;
627 struct cbuf buffer;
628 struct cbuf *bufp = &buffer;
629
630 /* fid[4] afid[4] uname[s] aname[s] */
631 size = 4 + 4 + 2 + 2;
632 if (uname)
633 size += strlen(uname);
634
635 if (aname)
636 size += strlen(aname);
637
638 if (dotu)
639 size += 4; /* n_uname */
640
641 fc = p9_create_common(bufp, size, P9_TATTACH);
642 if (IS_ERR(fc))
643 goto error;
644
645 p9_put_int32(bufp, fid, &fc->params.tattach.fid);
646 p9_put_int32(bufp, afid, &fc->params.tattach.afid);
647 p9_put_str(bufp, uname, &fc->params.tattach.uname);
648 p9_put_str(bufp, aname, &fc->params.tattach.aname);
649 if (dotu)
650 p9_put_int32(bufp, n_uname, &fc->params.tattach.n_uname);
651
652error:
653 return fc;
654}
655EXPORT_SYMBOL(p9_create_tattach);
656
657/**
658 * p9_create_tflush - allocates and creates a T_FLUSH request
659 * @oldtag: tag id for the transaction we are attempting to cancel
660 *
661 */
662
663struct p9_fcall *p9_create_tflush(u16 oldtag)
664{
665 int size;
666 struct p9_fcall *fc;
667 struct cbuf buffer;
668 struct cbuf *bufp = &buffer;
669
670 size = 2; /* oldtag[2] */
671 fc = p9_create_common(bufp, size, P9_TFLUSH);
672 if (IS_ERR(fc))
673 goto error;
674
675 p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
676
677 if (buf_check_overflow(bufp)) {
678 kfree(fc);
679 fc = ERR_PTR(-ENOMEM);
680 }
681error:
682 return fc;
683}
684EXPORT_SYMBOL(p9_create_tflush);
685
686/**
687 * p9_create_twalk - allocates and creates a T_FLUSH request
688 * @fid: handle we are traversing from
689 * @newfid: a new handle for this transaction
690 * @nwname: number of path elements to traverse
691 * @wnames: array of path elements
692 *
693 */
694
695struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
696 char **wnames)
697{
698 int i, size;
699 struct p9_fcall *fc;
700 struct cbuf buffer;
701 struct cbuf *bufp = &buffer;
702
703 if (nwname > P9_MAXWELEM) {
704 P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM);
705 return NULL;
706 }
707
708 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
709 for (i = 0; i < nwname; i++) {
710 size += 2 + strlen(wnames[i]); /* wname[s] */
711 }
712
713 fc = p9_create_common(bufp, size, P9_TWALK);
714 if (IS_ERR(fc))
715 goto error;
716
717 p9_put_int32(bufp, fid, &fc->params.twalk.fid);
718 p9_put_int32(bufp, newfid, &fc->params.twalk.newfid);
719 p9_put_int16(bufp, nwname, &fc->params.twalk.nwname);
720 for (i = 0; i < nwname; i++) {
721 p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
722 }
723
724 if (buf_check_overflow(bufp)) {
725 kfree(fc);
726 fc = ERR_PTR(-ENOMEM);
727 }
728error:
729 return fc;
730}
731EXPORT_SYMBOL(p9_create_twalk);
732
733/**
734 * p9_create_topen - allocates and creates a T_OPEN request
735 * @fid: handle we are trying to open
736 * @mode: what mode we are trying to open the file in
737 *
738 */
739
740struct p9_fcall *p9_create_topen(u32 fid, u8 mode)
741{
742 int size;
743 struct p9_fcall *fc;
744 struct cbuf buffer;
745 struct cbuf *bufp = &buffer;
746
747 size = 4 + 1; /* fid[4] mode[1] */
748 fc = p9_create_common(bufp, size, P9_TOPEN);
749 if (IS_ERR(fc))
750 goto error;
751
752 p9_put_int32(bufp, fid, &fc->params.topen.fid);
753 p9_put_int8(bufp, mode, &fc->params.topen.mode);
754
755 if (buf_check_overflow(bufp)) {
756 kfree(fc);
757 fc = ERR_PTR(-ENOMEM);
758 }
759error:
760 return fc;
761}
762EXPORT_SYMBOL(p9_create_topen);
763
764/**
765 * p9_create_tcreate - allocates and creates a T_CREATE request
766 * @fid: handle of directory we are trying to create in
767 * @name: name of the file we are trying to create
768 * @perm: permissions for the file we are trying to create
769 * @mode: what mode we are trying to open the file in
770 * @extension: 9p2000.u extension string (for special files)
771 * @dotu: 9p2000.u enabled flag
772 *
773 * Note: Plan 9 create semantics include opening the resulting file
774 * which is why mode is included.
775 */
776
777struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
778 char *extension, int dotu)
779{
780 int size;
781 struct p9_fcall *fc;
782 struct cbuf buffer;
783 struct cbuf *bufp = &buffer;
784
785 /* fid[4] name[s] perm[4] mode[1] */
786 size = 4 + 2 + strlen(name) + 4 + 1;
787 if (dotu) {
788 size += 2 + /* extension[s] */
789 (extension == NULL ? 0 : strlen(extension));
790 }
791
792 fc = p9_create_common(bufp, size, P9_TCREATE);
793 if (IS_ERR(fc))
794 goto error;
795
796 p9_put_int32(bufp, fid, &fc->params.tcreate.fid);
797 p9_put_str(bufp, name, &fc->params.tcreate.name);
798 p9_put_int32(bufp, perm, &fc->params.tcreate.perm);
799 p9_put_int8(bufp, mode, &fc->params.tcreate.mode);
800 if (dotu)
801 p9_put_str(bufp, extension, &fc->params.tcreate.extension);
802
803 if (buf_check_overflow(bufp)) {
804 kfree(fc);
805 fc = ERR_PTR(-ENOMEM);
806 }
807error:
808 return fc;
809}
810EXPORT_SYMBOL(p9_create_tcreate);
811
812/**
813 * p9_create_tread - allocates and creates a T_READ request
814 * @fid: handle of the file we are trying to read
815 * @offset: offset to start reading from
816 * @count: how many bytes to read
817 */
818
819struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count)
820{
821 int size;
822 struct p9_fcall *fc;
823 struct cbuf buffer;
824 struct cbuf *bufp = &buffer;
825
826 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
827 fc = p9_create_common(bufp, size, P9_TREAD);
828 if (IS_ERR(fc))
829 goto error;
830
831 p9_put_int32(bufp, fid, &fc->params.tread.fid);
832 p9_put_int64(bufp, offset, &fc->params.tread.offset);
833 p9_put_int32(bufp, count, &fc->params.tread.count);
834
835 if (buf_check_overflow(bufp)) {
836 kfree(fc);
837 fc = ERR_PTR(-ENOMEM);
838 }
839error:
840 return fc;
841}
842EXPORT_SYMBOL(p9_create_tread);
843
844/**
845 * p9_create_twrite - allocates and creates a T_WRITE request from the kernel
846 * @fid: handle of the file we are trying to write
847 * @offset: offset to start writing at
848 * @count: how many bytes to write
849 * @data: data to write
850 *
851 * This function will create a requst with data buffers from the kernel
852 * such as the page cache.
853 */
854
855struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count,
856 const char *data)
857{
858 int size, err;
859 struct p9_fcall *fc;
860 struct cbuf buffer;
861 struct cbuf *bufp = &buffer;
862
863 /* fid[4] offset[8] count[4] data[count] */
864 size = 4 + 8 + 4 + count;
865 fc = p9_create_common(bufp, size, P9_TWRITE);
866 if (IS_ERR(fc))
867 goto error;
868
869 p9_put_int32(bufp, fid, &fc->params.twrite.fid);
870 p9_put_int64(bufp, offset, &fc->params.twrite.offset);
871 p9_put_int32(bufp, count, &fc->params.twrite.count);
872 err = p9_put_data(bufp, data, count, &fc->params.twrite.data);
873 if (err) {
874 kfree(fc);
875 fc = ERR_PTR(err);
876 goto error;
877 }
878
879 if (buf_check_overflow(bufp)) {
880 kfree(fc);
881 fc = ERR_PTR(-ENOMEM);
882 }
883error:
884 return fc;
885}
886EXPORT_SYMBOL(p9_create_twrite);
887
888/**
889 * p9_create_twrite_u - allocates and creates a T_WRITE request from userspace
890 * @fid: handle of the file we are trying to write
891 * @offset: offset to start writing at
892 * @count: how many bytes to write
893 * @data: data to write
894 *
895 * This function will create a request with data buffers from userspace
896 */
897
898struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count,
899 const char __user *data)
900{
901 int size, err;
902 struct p9_fcall *fc;
903 struct cbuf buffer;
904 struct cbuf *bufp = &buffer;
905
906 /* fid[4] offset[8] count[4] data[count] */
907 size = 4 + 8 + 4 + count;
908 fc = p9_create_common(bufp, size, P9_TWRITE);
909 if (IS_ERR(fc))
910 goto error;
911
912 p9_put_int32(bufp, fid, &fc->params.twrite.fid);
913 p9_put_int64(bufp, offset, &fc->params.twrite.offset);
914 p9_put_int32(bufp, count, &fc->params.twrite.count);
915 err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data);
916 if (err) {
917 kfree(fc);
918 fc = ERR_PTR(err);
919 goto error;
920 }
921
922 if (buf_check_overflow(bufp)) {
923 kfree(fc);
924 fc = ERR_PTR(-ENOMEM);
925 }
926error:
927 return fc;
928}
929EXPORT_SYMBOL(p9_create_twrite_u);
930
931/**
932 * p9_create_tclunk - allocate a request to forget about a file handle
933 * @fid: handle of the file we closing or forgetting about
934 *
935 * clunk is used both to close open files and to discard transient handles
936 * which may be created during meta-data operations and hierarchy traversal.
937 */
938
939struct p9_fcall *p9_create_tclunk(u32 fid)
940{
941 int size;
942 struct p9_fcall *fc;
943 struct cbuf buffer;
944 struct cbuf *bufp = &buffer;
945
946 size = 4; /* fid[4] */
947 fc = p9_create_common(bufp, size, P9_TCLUNK);
948 if (IS_ERR(fc))
949 goto error;
950
951 p9_put_int32(bufp, fid, &fc->params.tclunk.fid);
952
953 if (buf_check_overflow(bufp)) {
954 kfree(fc);
955 fc = ERR_PTR(-ENOMEM);
956 }
957error:
958 return fc;
959}
960EXPORT_SYMBOL(p9_create_tclunk);
961
962/**
963 * p9_create_tremove - allocate and create a request to remove a file
964 * @fid: handle of the file or directory we are removing
965 *
966 */
967
968struct p9_fcall *p9_create_tremove(u32 fid)
969{
970 int size;
971 struct p9_fcall *fc;
972 struct cbuf buffer;
973 struct cbuf *bufp = &buffer;
974
975 size = 4; /* fid[4] */
976 fc = p9_create_common(bufp, size, P9_TREMOVE);
977 if (IS_ERR(fc))
978 goto error;
979
980 p9_put_int32(bufp, fid, &fc->params.tremove.fid);
981
982 if (buf_check_overflow(bufp)) {
983 kfree(fc);
984 fc = ERR_PTR(-ENOMEM);
985 }
986error:
987 return fc;
988}
989EXPORT_SYMBOL(p9_create_tremove);
990
991/**
992 * p9_create_tstat - allocate and populate a request for attributes
993 * @fid: handle of the file or directory we are trying to get the attributes of
994 *
995 */
996
997struct p9_fcall *p9_create_tstat(u32 fid)
998{
999 int size;
1000 struct p9_fcall *fc;
1001 struct cbuf buffer;
1002 struct cbuf *bufp = &buffer;
1003
1004 size = 4; /* fid[4] */
1005 fc = p9_create_common(bufp, size, P9_TSTAT);
1006 if (IS_ERR(fc))
1007 goto error;
1008
1009 p9_put_int32(bufp, fid, &fc->params.tstat.fid);
1010
1011 if (buf_check_overflow(bufp)) {
1012 kfree(fc);
1013 fc = ERR_PTR(-ENOMEM);
1014 }
1015error:
1016 return fc;
1017}
1018EXPORT_SYMBOL(p9_create_tstat);
1019
1020/**
1021 * p9_create_tstat - allocate and populate a request to change attributes
1022 * @fid: handle of the file or directory we are trying to change
1023 * @wstat: &p9_stat structure with attributes we wish to set
1024 * @dotu: 9p2000.u enabled flag
1025 *
1026 */
1027
1028struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat,
1029 int dotu)
1030{
1031 int size, statsz;
1032 struct p9_fcall *fc;
1033 struct cbuf buffer;
1034 struct cbuf *bufp = &buffer;
1035
1036 statsz = p9_size_wstat(wstat, dotu);
1037 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
1038 fc = p9_create_common(bufp, size, P9_TWSTAT);
1039 if (IS_ERR(fc))
1040 goto error;
1041
1042 p9_put_int32(bufp, fid, &fc->params.twstat.fid);
1043 buf_put_int16(bufp, statsz + 2);
1044 p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu);
1045
1046 if (buf_check_overflow(bufp)) {
1047 kfree(fc);
1048 fc = ERR_PTR(-ENOMEM);
1049 }
1050error:
1051 return fc;
1052}
1053EXPORT_SYMBOL(p9_create_twstat);
1054
diff --git a/net/9p/fcprint.c b/net/9p/fcprint.c
deleted file mode 100644
index 53dd8e28dd8a..000000000000
--- a/net/9p/fcprint.c
+++ /dev/null
@@ -1,366 +0,0 @@
1/*
2 * net/9p/fcprint.c
3 *
4 * Print 9P call.
5 *
6 * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to:
19 * Free Software Foundation
20 * 51 Franklin Street, Fifth Floor
21 * Boston, MA 02111-1301 USA
22 *
23 */
24#include <linux/module.h>
25#include <linux/errno.h>
26#include <linux/fs.h>
27#include <linux/idr.h>
28#include <net/9p/9p.h>
29
30#ifdef CONFIG_NET_9P_DEBUG
31
32static int
33p9_printqid(char *buf, int buflen, struct p9_qid *q)
34{
35 int n;
36 char b[10];
37
38 n = 0;
39 if (q->type & P9_QTDIR)
40 b[n++] = 'd';
41 if (q->type & P9_QTAPPEND)
42 b[n++] = 'a';
43 if (q->type & P9_QTAUTH)
44 b[n++] = 'A';
45 if (q->type & P9_QTEXCL)
46 b[n++] = 'l';
47 if (q->type & P9_QTTMP)
48 b[n++] = 't';
49 if (q->type & P9_QTSYMLINK)
50 b[n++] = 'L';
51 b[n] = '\0';
52
53 return scnprintf(buf, buflen, "(%.16llx %x %s)",
54 (long long int) q->path, q->version, b);
55}
56
57static int
58p9_printperm(char *buf, int buflen, int perm)
59{
60 int n;
61 char b[15];
62
63 n = 0;
64 if (perm & P9_DMDIR)
65 b[n++] = 'd';
66 if (perm & P9_DMAPPEND)
67 b[n++] = 'a';
68 if (perm & P9_DMAUTH)
69 b[n++] = 'A';
70 if (perm & P9_DMEXCL)
71 b[n++] = 'l';
72 if (perm & P9_DMTMP)
73 b[n++] = 't';
74 if (perm & P9_DMDEVICE)
75 b[n++] = 'D';
76 if (perm & P9_DMSOCKET)
77 b[n++] = 'S';
78 if (perm & P9_DMNAMEDPIPE)
79 b[n++] = 'P';
80 if (perm & P9_DMSYMLINK)
81 b[n++] = 'L';
82 b[n] = '\0';
83
84 return scnprintf(buf, buflen, "%s%03o", b, perm&077);
85}
86
87static int
88p9_printstat(char *buf, int buflen, struct p9_stat *st, int extended)
89{
90 int n;
91
92 n = scnprintf(buf, buflen, "'%.*s' '%.*s'", st->name.len,
93 st->name.str, st->uid.len, st->uid.str);
94 if (extended)
95 n += scnprintf(buf+n, buflen-n, "(%d)", st->n_uid);
96
97 n += scnprintf(buf+n, buflen-n, " '%.*s'", st->gid.len, st->gid.str);
98 if (extended)
99 n += scnprintf(buf+n, buflen-n, "(%d)", st->n_gid);
100
101 n += scnprintf(buf+n, buflen-n, " '%.*s'", st->muid.len, st->muid.str);
102 if (extended)
103 n += scnprintf(buf+n, buflen-n, "(%d)", st->n_muid);
104
105 n += scnprintf(buf+n, buflen-n, " q ");
106 n += p9_printqid(buf+n, buflen-n, &st->qid);
107 n += scnprintf(buf+n, buflen-n, " m ");
108 n += p9_printperm(buf+n, buflen-n, st->mode);
109 n += scnprintf(buf+n, buflen-n, " at %d mt %d l %lld",
110 st->atime, st->mtime, (long long int) st->length);
111
112 if (extended)
113 n += scnprintf(buf+n, buflen-n, " ext '%.*s'",
114 st->extension.len, st->extension.str);
115
116 return n;
117}
118
119static int
120p9_dumpdata(char *buf, int buflen, u8 *data, int datalen)
121{
122 int i, n;
123
124 i = n = 0;
125 while (i < datalen) {
126 n += scnprintf(buf + n, buflen - n, "%02x", data[i]);
127 if (i%4 == 3)
128 n += scnprintf(buf + n, buflen - n, " ");
129 if (i%32 == 31)
130 n += scnprintf(buf + n, buflen - n, "\n");
131
132 i++;
133 }
134 n += scnprintf(buf + n, buflen - n, "\n");
135
136 return n;
137}
138
139static int
140p9_printdata(char *buf, int buflen, u8 *data, int datalen)
141{
142 return p9_dumpdata(buf, buflen, data, datalen < 16?datalen:16);
143}
144
145/**
146 * p9_printfcall - decode and print a protocol structure into a buffer
147 * @buf: buffer to deposit decoded structure into
148 * @buflen: available space in buffer
149 * @fc: protocol rpc structure of type &p9_fcall
150 * @extended: whether or not session is operating with extended protocol
151 */
152
153int
154p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
155{
156 int i, ret, type, tag;
157
158 if (!fc)
159 return scnprintf(buf, buflen, "<NULL>");
160
161 type = fc->id;
162 tag = fc->tag;
163
164 ret = 0;
165 switch (type) {
166 case P9_TVERSION:
167 ret += scnprintf(buf+ret, buflen-ret,
168 "Tversion tag %u msize %u version '%.*s'", tag,
169 fc->params.tversion.msize,
170 fc->params.tversion.version.len,
171 fc->params.tversion.version.str);
172 break;
173
174 case P9_RVERSION:
175 ret += scnprintf(buf+ret, buflen-ret,
176 "Rversion tag %u msize %u version '%.*s'", tag,
177 fc->params.rversion.msize,
178 fc->params.rversion.version.len,
179 fc->params.rversion.version.str);
180 break;
181
182 case P9_TAUTH:
183 ret += scnprintf(buf+ret, buflen-ret,
184 "Tauth tag %u afid %d uname '%.*s' aname '%.*s'", tag,
185 fc->params.tauth.afid, fc->params.tauth.uname.len,
186 fc->params.tauth.uname.str, fc->params.tauth.aname.len,
187 fc->params.tauth.aname.str);
188 break;
189
190 case P9_RAUTH:
191 ret += scnprintf(buf+ret, buflen-ret, "Rauth tag %u qid ", tag);
192 p9_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid);
193 break;
194
195 case P9_TATTACH:
196 ret += scnprintf(buf+ret, buflen-ret,
197 "Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'", tag,
198 fc->params.tattach.fid, fc->params.tattach.afid,
199 fc->params.tattach.uname.len, fc->params.tattach.uname.str,
200 fc->params.tattach.aname.len, fc->params.tattach.aname.str);
201 break;
202
203 case P9_RATTACH:
204 ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ",
205 tag);
206 p9_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid);
207 break;
208
209 case P9_RERROR:
210 ret += scnprintf(buf+ret, buflen-ret,
211 "Rerror tag %u ename '%.*s'", tag,
212 fc->params.rerror.error.len,
213 fc->params.rerror.error.str);
214 if (extended)
215 ret += scnprintf(buf+ret, buflen-ret, " ecode %d\n",
216 fc->params.rerror.errno);
217 break;
218
219 case P9_TFLUSH:
220 ret += scnprintf(buf+ret, buflen-ret, "Tflush tag %u oldtag %u",
221 tag, fc->params.tflush.oldtag);
222 break;
223
224 case P9_RFLUSH:
225 ret += scnprintf(buf+ret, buflen-ret, "Rflush tag %u", tag);
226 break;
227
228 case P9_TWALK:
229 ret += scnprintf(buf+ret, buflen-ret,
230 "Twalk tag %u fid %d newfid %d nwname %d", tag,
231 fc->params.twalk.fid, fc->params.twalk.newfid,
232 fc->params.twalk.nwname);
233 for (i = 0; i < fc->params.twalk.nwname; i++)
234 ret += scnprintf(buf+ret, buflen-ret, " '%.*s'",
235 fc->params.twalk.wnames[i].len,
236 fc->params.twalk.wnames[i].str);
237 break;
238
239 case P9_RWALK:
240 ret += scnprintf(buf+ret, buflen-ret, "Rwalk tag %u nwqid %d",
241 tag, fc->params.rwalk.nwqid);
242 for (i = 0; i < fc->params.rwalk.nwqid; i++)
243 ret += p9_printqid(buf+ret, buflen-ret,
244 &fc->params.rwalk.wqids[i]);
245 break;
246
247 case P9_TOPEN:
248 ret += scnprintf(buf+ret, buflen-ret,
249 "Topen tag %u fid %d mode %d", tag,
250 fc->params.topen.fid, fc->params.topen.mode);
251 break;
252
253 case P9_ROPEN:
254 ret += scnprintf(buf+ret, buflen-ret, "Ropen tag %u", tag);
255 ret += p9_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid);
256 ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
257 fc->params.ropen.iounit);
258 break;
259
260 case P9_TCREATE:
261 ret += scnprintf(buf+ret, buflen-ret,
262 "Tcreate tag %u fid %d name '%.*s' perm ", tag,
263 fc->params.tcreate.fid, fc->params.tcreate.name.len,
264 fc->params.tcreate.name.str);
265
266 ret += p9_printperm(buf+ret, buflen-ret,
267 fc->params.tcreate.perm);
268 ret += scnprintf(buf+ret, buflen-ret, " mode %d",
269 fc->params.tcreate.mode);
270 break;
271
272 case P9_RCREATE:
273 ret += scnprintf(buf+ret, buflen-ret, "Rcreate tag %u", tag);
274 ret += p9_printqid(buf+ret, buflen-ret,
275 &fc->params.rcreate.qid);
276 ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
277 fc->params.rcreate.iounit);
278 break;
279
280 case P9_TREAD:
281 ret += scnprintf(buf+ret, buflen-ret,
282 "Tread tag %u fid %d offset %lld count %u", tag,
283 fc->params.tread.fid,
284 (long long int) fc->params.tread.offset,
285 fc->params.tread.count);
286 break;
287
288 case P9_RREAD:
289 ret += scnprintf(buf+ret, buflen-ret,
290 "Rread tag %u count %u data ", tag,
291 fc->params.rread.count);
292 ret += p9_printdata(buf+ret, buflen-ret, fc->params.rread.data,
293 fc->params.rread.count);
294 break;
295
296 case P9_TWRITE:
297 ret += scnprintf(buf+ret, buflen-ret,
298 "Twrite tag %u fid %d offset %lld count %u data ",
299 tag, fc->params.twrite.fid,
300 (long long int) fc->params.twrite.offset,
301 fc->params.twrite.count);
302 ret += p9_printdata(buf+ret, buflen-ret, fc->params.twrite.data,
303 fc->params.twrite.count);
304 break;
305
306 case P9_RWRITE:
307 ret += scnprintf(buf+ret, buflen-ret, "Rwrite tag %u count %u",
308 tag, fc->params.rwrite.count);
309 break;
310
311 case P9_TCLUNK:
312 ret += scnprintf(buf+ret, buflen-ret, "Tclunk tag %u fid %d",
313 tag, fc->params.tclunk.fid);
314 break;
315
316 case P9_RCLUNK:
317 ret += scnprintf(buf+ret, buflen-ret, "Rclunk tag %u", tag);
318 break;
319
320 case P9_TREMOVE:
321 ret += scnprintf(buf+ret, buflen-ret, "Tremove tag %u fid %d",
322 tag, fc->params.tremove.fid);
323 break;
324
325 case P9_RREMOVE:
326 ret += scnprintf(buf+ret, buflen-ret, "Rremove tag %u", tag);
327 break;
328
329 case P9_TSTAT:
330 ret += scnprintf(buf+ret, buflen-ret, "Tstat tag %u fid %d",
331 tag, fc->params.tstat.fid);
332 break;
333
334 case P9_RSTAT:
335 ret += scnprintf(buf+ret, buflen-ret, "Rstat tag %u ", tag);
336 ret += p9_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat,
337 extended);
338 break;
339
340 case P9_TWSTAT:
341 ret += scnprintf(buf+ret, buflen-ret, "Twstat tag %u fid %d ",
342 tag, fc->params.twstat.fid);
343 ret += p9_printstat(buf+ret, buflen-ret,
344 &fc->params.twstat.stat, extended);
345 break;
346
347 case P9_RWSTAT:
348 ret += scnprintf(buf+ret, buflen-ret, "Rwstat tag %u", tag);
349 break;
350
351 default:
352 ret += scnprintf(buf+ret, buflen-ret, "unknown type %d", type);
353 break;
354 }
355
356 return ret;
357}
358#else
359int
360p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
361{
362 return 0;
363}
364#endif /* CONFIG_NET_9P_DEBUG */
365EXPORT_SYMBOL(p9_printfcall);
366
diff --git a/net/9p/mod.c b/net/9p/mod.c
index 1084feb24cb0..cf8a4128cd5c 100644
--- a/net/9p/mod.c
+++ b/net/9p/mod.c
@@ -29,6 +29,7 @@
29#include <net/9p/9p.h> 29#include <net/9p/9p.h>
30#include <linux/fs.h> 30#include <linux/fs.h>
31#include <linux/parser.h> 31#include <linux/parser.h>
32#include <net/9p/client.h>
32#include <net/9p/transport.h> 33#include <net/9p/transport.h>
33#include <linux/list.h> 34#include <linux/list.h>
34#include <linux/spinlock.h> 35#include <linux/spinlock.h>
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
new file mode 100644
index 000000000000..29be52439086
--- /dev/null
+++ b/net/9p/protocol.c
@@ -0,0 +1,558 @@
1/*
2 * net/9p/protocol.c
3 *
4 * 9P Protocol Support Code
5 *
6 * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
7 *
8 * Base on code from Anthony Liguori <aliguori@us.ibm.com>
9 * Copyright (C) 2008 by IBM, Corp.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to:
22 * Free Software Foundation
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02111-1301 USA
25 *
26 */
27
28#include <linux/module.h>
29#include <linux/errno.h>
30#include <linux/uaccess.h>
31#include <linux/sched.h>
32#include <net/9p/9p.h>
33#include <net/9p/client.h>
34#include "protocol.h"
35
36#ifndef MIN
37#define MIN(a, b) (((a) < (b)) ? (a) : (b))
38#endif
39
40#ifndef MAX
41#define MAX(a, b) (((a) > (b)) ? (a) : (b))
42#endif
43
44#ifndef offset_of
45#define offset_of(type, memb) \
46 ((unsigned long)(&((type *)0)->memb))
47#endif
48#ifndef container_of
49#define container_of(obj, type, memb) \
50 ((type *)(((char *)obj) - offset_of(type, memb)))
51#endif
52
53static int
54p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...);
55
56void
57p9pdu_dump(int way, struct p9_fcall *pdu)
58{
59 int i, n;
60 u8 *data = pdu->sdata;
61 int datalen = pdu->size;
62 char buf[255];
63 int buflen = 255;
64
65 i = n = 0;
66 if (datalen > (buflen-16))
67 datalen = buflen-16;
68 while (i < datalen) {
69 n += scnprintf(buf + n, buflen - n, "%02x ", data[i]);
70 if (i%4 == 3)
71 n += scnprintf(buf + n, buflen - n, " ");
72 if (i%32 == 31)
73 n += scnprintf(buf + n, buflen - n, "\n");
74
75 i++;
76 }
77 n += scnprintf(buf + n, buflen - n, "\n");
78
79 if (way)
80 P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
81 else
82 P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
83}
84EXPORT_SYMBOL(p9pdu_dump);
85
86void p9stat_free(struct p9_wstat *stbuf)
87{
88 kfree(stbuf->name);
89 kfree(stbuf->uid);
90 kfree(stbuf->gid);
91 kfree(stbuf->muid);
92 kfree(stbuf->extension);
93}
94EXPORT_SYMBOL(p9stat_free);
95
96static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
97{
98 size_t len = MIN(pdu->size - pdu->offset, size);
99 memcpy(data, &pdu->sdata[pdu->offset], len);
100 pdu->offset += len;
101 return size - len;
102}
103
104static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
105{
106 size_t len = MIN(pdu->capacity - pdu->size, size);
107 memcpy(&pdu->sdata[pdu->size], data, len);
108 pdu->size += len;
109 return size - len;
110}
111
112static size_t
113pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
114{
115 size_t len = MIN(pdu->capacity - pdu->size, size);
116 int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
117 if (err)
118 printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
119
120 pdu->size += len;
121 return size - len;
122}
123
124/*
125 b - int8_t
126 w - int16_t
127 d - int32_t
128 q - int64_t
129 s - string
130 S - stat
131 Q - qid
132 D - data blob (int32_t size followed by void *, results are not freed)
133 T - array of strings (int16_t count, followed by strings)
134 R - array of qids (int16_t count, followed by qids)
135 ? - if optional = 1, continue parsing
136*/
137
138static int
139p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
140{
141 const char *ptr;
142 int errcode = 0;
143
144 for (ptr = fmt; *ptr; ptr++) {
145 switch (*ptr) {
146 case 'b':{
147 int8_t *val = va_arg(ap, int8_t *);
148 if (pdu_read(pdu, val, sizeof(*val))) {
149 errcode = -EFAULT;
150 break;
151 }
152 }
153 break;
154 case 'w':{
155 int16_t *val = va_arg(ap, int16_t *);
156 if (pdu_read(pdu, val, sizeof(*val))) {
157 errcode = -EFAULT;
158 break;
159 }
160 *val = cpu_to_le16(*val);
161 }
162 break;
163 case 'd':{
164 int32_t *val = va_arg(ap, int32_t *);
165 if (pdu_read(pdu, val, sizeof(*val))) {
166 errcode = -EFAULT;
167 break;
168 }
169 *val = cpu_to_le32(*val);
170 }
171 break;
172 case 'q':{
173 int64_t *val = va_arg(ap, int64_t *);
174 if (pdu_read(pdu, val, sizeof(*val))) {
175 errcode = -EFAULT;
176 break;
177 }
178 *val = cpu_to_le64(*val);
179 }
180 break;
181 case 's':{
182 char **ptr = va_arg(ap, char **);
183 int16_t len;
184 int size;
185
186 errcode = p9pdu_readf(pdu, optional, "w", &len);
187 if (errcode)
188 break;
189
190 size = MAX(len, 0);
191
192 *ptr = kmalloc(size + 1, GFP_KERNEL);
193 if (*ptr == NULL) {
194 errcode = -EFAULT;
195 break;
196 }
197 if (pdu_read(pdu, *ptr, size)) {
198 errcode = -EFAULT;
199 kfree(*ptr);
200 *ptr = NULL;
201 } else
202 (*ptr)[size] = 0;
203 }
204 break;
205 case 'Q':{
206 struct p9_qid *qid =
207 va_arg(ap, struct p9_qid *);
208
209 errcode = p9pdu_readf(pdu, optional, "bdq",
210 &qid->type, &qid->version,
211 &qid->path);
212 }
213 break;
214 case 'S':{
215 struct p9_wstat *stbuf =
216 va_arg(ap, struct p9_wstat *);
217
218 memset(stbuf, 0, sizeof(struct p9_wstat));
219 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
220 -1;
221 errcode =
222 p9pdu_readf(pdu, optional,
223 "wwdQdddqssss?sddd",
224 &stbuf->size, &stbuf->type,
225 &stbuf->dev, &stbuf->qid,
226 &stbuf->mode, &stbuf->atime,
227 &stbuf->mtime, &stbuf->length,
228 &stbuf->name, &stbuf->uid,
229 &stbuf->gid, &stbuf->muid,
230 &stbuf->extension,
231 &stbuf->n_uid, &stbuf->n_gid,
232 &stbuf->n_muid);
233 if (errcode)
234 p9stat_free(stbuf);
235 }
236 break;
237 case 'D':{
238 int32_t *count = va_arg(ap, int32_t *);
239 void **data = va_arg(ap, void **);
240
241 errcode =
242 p9pdu_readf(pdu, optional, "d", count);
243 if (!errcode) {
244 *count =
245 MIN(*count,
246 pdu->size - pdu->offset);
247 *data = &pdu->sdata[pdu->offset];
248 }
249 }
250 break;
251 case 'T':{
252 int16_t *nwname = va_arg(ap, int16_t *);
253 char ***wnames = va_arg(ap, char ***);
254
255 errcode =
256 p9pdu_readf(pdu, optional, "w", nwname);
257 if (!errcode) {
258 *wnames =
259 kmalloc(sizeof(char *) * *nwname,
260 GFP_KERNEL);
261 if (!*wnames)
262 errcode = -ENOMEM;
263 }
264
265 if (!errcode) {
266 int i;
267
268 for (i = 0; i < *nwname; i++) {
269 errcode =
270 p9pdu_readf(pdu, optional,
271 "s",
272 &(*wnames)[i]);
273 if (errcode)
274 break;
275 }
276 }
277
278 if (errcode) {
279 if (*wnames) {
280 int i;
281
282 for (i = 0; i < *nwname; i++)
283 kfree((*wnames)[i]);
284 }
285 kfree(*wnames);
286 *wnames = NULL;
287 }
288 }
289 break;
290 case 'R':{
291 int16_t *nwqid = va_arg(ap, int16_t *);
292 struct p9_qid **wqids =
293 va_arg(ap, struct p9_qid **);
294
295 *wqids = NULL;
296
297 errcode =
298 p9pdu_readf(pdu, optional, "w", nwqid);
299 if (!errcode) {
300 *wqids =
301 kmalloc(*nwqid *
302 sizeof(struct p9_qid),
303 GFP_KERNEL);
304 if (*wqids == NULL)
305 errcode = -ENOMEM;
306 }
307
308 if (!errcode) {
309 int i;
310
311 for (i = 0; i < *nwqid; i++) {
312 errcode =
313 p9pdu_readf(pdu, optional,
314 "Q",
315 &(*wqids)[i]);
316 if (errcode)
317 break;
318 }
319 }
320
321 if (errcode) {
322 kfree(*wqids);
323 *wqids = NULL;
324 }
325 }
326 break;
327 case '?':
328 if (!optional)
329 return 0;
330 break;
331 default:
332 BUG();
333 break;
334 }
335
336 if (errcode)
337 break;
338 }
339
340 return errcode;
341}
342
343int
344p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
345{
346 const char *ptr;
347 int errcode = 0;
348
349 for (ptr = fmt; *ptr; ptr++) {
350 switch (*ptr) {
351 case 'b':{
352 int8_t val = va_arg(ap, int);
353 if (pdu_write(pdu, &val, sizeof(val)))
354 errcode = -EFAULT;
355 }
356 break;
357 case 'w':{
358 int16_t val = va_arg(ap, int);
359 if (pdu_write(pdu, &val, sizeof(val)))
360 errcode = -EFAULT;
361 }
362 break;
363 case 'd':{
364 int32_t val = va_arg(ap, int32_t);
365 if (pdu_write(pdu, &val, sizeof(val)))
366 errcode = -EFAULT;
367 }
368 break;
369 case 'q':{
370 int64_t val = va_arg(ap, int64_t);
371 if (pdu_write(pdu, &val, sizeof(val)))
372 errcode = -EFAULT;
373 }
374 break;
375 case 's':{
376 const char *ptr = va_arg(ap, const char *);
377 int16_t len = 0;
378 if (ptr)
379 len = MIN(strlen(ptr), USHORT_MAX);
380
381 errcode = p9pdu_writef(pdu, optional, "w", len);
382 if (!errcode && pdu_write(pdu, ptr, len))
383 errcode = -EFAULT;
384 }
385 break;
386 case 'Q':{
387 const struct p9_qid *qid =
388 va_arg(ap, const struct p9_qid *);
389 errcode =
390 p9pdu_writef(pdu, optional, "bdq",
391 qid->type, qid->version,
392 qid->path);
393 } break;
394 case 'S':{
395 const struct p9_wstat *stbuf =
396 va_arg(ap, const struct p9_wstat *);
397 errcode =
398 p9pdu_writef(pdu, optional,
399 "wwdQdddqssss?sddd",
400 stbuf->size, stbuf->type,
401 stbuf->dev, &stbuf->qid,
402 stbuf->mode, stbuf->atime,
403 stbuf->mtime, stbuf->length,
404 stbuf->name, stbuf->uid,
405 stbuf->gid, stbuf->muid,
406 stbuf->extension, stbuf->n_uid,
407 stbuf->n_gid, stbuf->n_muid);
408 } break;
409 case 'D':{
410 int32_t count = va_arg(ap, int32_t);
411 const void *data = va_arg(ap, const void *);
412
413 errcode =
414 p9pdu_writef(pdu, optional, "d", count);
415 if (!errcode && pdu_write(pdu, data, count))
416 errcode = -EFAULT;
417 }
418 break;
419 case 'U':{
420 int32_t count = va_arg(ap, int32_t);
421 const char __user *udata =
422 va_arg(ap, const void *);
423 errcode =
424 p9pdu_writef(pdu, optional, "d", count);
425 if (!errcode && pdu_write_u(pdu, udata, count))
426 errcode = -EFAULT;
427 }
428 break;
429 case 'T':{
430 int16_t nwname = va_arg(ap, int);
431 const char **wnames = va_arg(ap, const char **);
432
433 errcode =
434 p9pdu_writef(pdu, optional, "w", nwname);
435 if (!errcode) {
436 int i;
437
438 for (i = 0; i < nwname; i++) {
439 errcode =
440 p9pdu_writef(pdu, optional,
441 "s",
442 wnames[i]);
443 if (errcode)
444 break;
445 }
446 }
447 }
448 break;
449 case 'R':{
450 int16_t nwqid = va_arg(ap, int);
451 struct p9_qid *wqids =
452 va_arg(ap, struct p9_qid *);
453
454 errcode =
455 p9pdu_writef(pdu, optional, "w", nwqid);
456 if (!errcode) {
457 int i;
458
459 for (i = 0; i < nwqid; i++) {
460 errcode =
461 p9pdu_writef(pdu, optional,
462 "Q",
463 &wqids[i]);
464 if (errcode)
465 break;
466 }
467 }
468 }
469 break;
470 case '?':
471 if (!optional)
472 return 0;
473 break;
474 default:
475 BUG();
476 break;
477 }
478
479 if (errcode)
480 break;
481 }
482
483 return errcode;
484}
485
486int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...)
487{
488 va_list ap;
489 int ret;
490
491 va_start(ap, fmt);
492 ret = p9pdu_vreadf(pdu, optional, fmt, ap);
493 va_end(ap);
494
495 return ret;
496}
497
498static int
499p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...)
500{
501 va_list ap;
502 int ret;
503
504 va_start(ap, fmt);
505 ret = p9pdu_vwritef(pdu, optional, fmt, ap);
506 va_end(ap);
507
508 return ret;
509}
510
511int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
512{
513 struct p9_fcall fake_pdu;
514 int ret;
515
516 fake_pdu.size = len;
517 fake_pdu.capacity = len;
518 fake_pdu.sdata = buf;
519 fake_pdu.offset = 0;
520
521 ret = p9pdu_readf(&fake_pdu, dotu, "S", st);
522 if (ret) {
523 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
524 p9pdu_dump(1, &fake_pdu);
525 }
526
527 return ret;
528}
529EXPORT_SYMBOL(p9stat_read);
530
531int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
532{
533 return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
534}
535
536int p9pdu_finalize(struct p9_fcall *pdu)
537{
538 int size = pdu->size;
539 int err;
540
541 pdu->size = 0;
542 err = p9pdu_writef(pdu, 0, "d", size);
543 pdu->size = size;
544
545 if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
546 p9pdu_dump(0, pdu);
547
548 P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
549 pdu->id, pdu->tag);
550
551 return err;
552}
553
554void p9pdu_reset(struct p9_fcall *pdu)
555{
556 pdu->offset = 0;
557 pdu->size = 0;
558}
diff --git a/net/9p/protocol.h b/net/9p/protocol.h
new file mode 100644
index 000000000000..ccde462e7ac5
--- /dev/null
+++ b/net/9p/protocol.h
@@ -0,0 +1,34 @@
1/*
2 * net/9p/protocol.h
3 *
4 * 9P Protocol Support Code
5 *
6 * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
7 *
8 * Base on code from Anthony Liguori <aliguori@us.ibm.com>
9 * Copyright (C) 2008 by IBM, Corp.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to:
22 * Free Software Foundation
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02111-1301 USA
25 *
26 */
27
28int
29p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap);
30int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...);
31int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type);
32int p9pdu_finalize(struct p9_fcall *pdu);
33void p9pdu_dump(int, struct p9_fcall *);
34void p9pdu_reset(struct p9_fcall *pdu);
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 6dabbdb66651..be65d8242fd2 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -39,12 +39,11 @@
39#include <linux/file.h> 39#include <linux/file.h>
40#include <linux/parser.h> 40#include <linux/parser.h>
41#include <net/9p/9p.h> 41#include <net/9p/9p.h>
42#include <net/9p/client.h>
42#include <net/9p/transport.h> 43#include <net/9p/transport.h>
43 44
44#define P9_PORT 564 45#define P9_PORT 564
45#define MAX_SOCK_BUF (64*1024) 46#define MAX_SOCK_BUF (64*1024)
46#define ERREQFLUSH 1
47#define SCHED_TIMEOUT 10
48#define MAXPOLLWADDR 2 47#define MAXPOLLWADDR 2
49 48
50/** 49/**
@@ -61,7 +60,6 @@ struct p9_fd_opts {
61 u16 port; 60 u16 port;
62}; 61};
63 62
64
65/** 63/**
66 * struct p9_trans_fd - transport state 64 * struct p9_trans_fd - transport state
67 * @rd: reference to file to read from 65 * @rd: reference to file to read from
@@ -100,60 +98,22 @@ enum {
100 Wpending = 8, /* can write */ 98 Wpending = 8, /* can write */
101}; 99};
102 100
103enum { 101struct p9_poll_wait {
104 None, 102 struct p9_conn *conn;
105 Flushing, 103 wait_queue_t wait;
106 Flushed, 104 wait_queue_head_t *wait_addr;
107};
108
109struct p9_req;
110typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
111
112/**
113 * struct p9_req - fd mux encoding of an rpc transaction
114 * @lock: protects req_list
115 * @tag: numeric tag for rpc transaction
116 * @tcall: request &p9_fcall structure
117 * @rcall: response &p9_fcall structure
118 * @err: error state
119 * @cb: callback for when response is received
120 * @cba: argument to pass to callback
121 * @flush: flag to indicate RPC has been flushed
122 * @req_list: list link for higher level objects to chain requests
123 *
124 */
125
126struct p9_req {
127 spinlock_t lock;
128 int tag;
129 struct p9_fcall *tcall;
130 struct p9_fcall *rcall;
131 int err;
132 p9_conn_req_callback cb;
133 void *cba;
134 int flush;
135 struct list_head req_list;
136};
137
138struct p9_mux_poll_task {
139 struct task_struct *task;
140 struct list_head mux_list;
141 int muxnum;
142}; 105};
143 106
144/** 107/**
145 * struct p9_conn - fd mux connection state information 108 * struct p9_conn - fd mux connection state information
146 * @lock: protects mux_list (?)
147 * @mux_list: list link for mux to manage multiple connections (?) 109 * @mux_list: list link for mux to manage multiple connections (?)
148 * @poll_task: task polling on this connection 110 * @client: reference to client instance for this connection
149 * @msize: maximum size for connection (dup)
150 * @extended: 9p2000.u flag (dup)
151 * @trans: reference to transport instance for this connection
152 * @tagpool: id accounting for transactions
153 * @err: error state 111 * @err: error state
154 * @req_list: accounting for requests which have been sent 112 * @req_list: accounting for requests which have been sent
155 * @unsent_req_list: accounting for requests that haven't been sent 113 * @unsent_req_list: accounting for requests that haven't been sent
156 * @rcall: current response &p9_fcall structure 114 * @req: current request being processed (if any)
115 * @tmp_buf: temporary buffer to read in header
116 * @rsize: amount to read for current frame
157 * @rpos: read position in current frame 117 * @rpos: read position in current frame
158 * @rbuf: current read buffer 118 * @rbuf: current read buffer
159 * @wpos: write position for current frame 119 * @wpos: write position for current frame
@@ -169,409 +129,300 @@ struct p9_mux_poll_task {
169 */ 129 */
170 130
171struct p9_conn { 131struct p9_conn {
172 spinlock_t lock; /* protect lock structure */
173 struct list_head mux_list; 132 struct list_head mux_list;
174 struct p9_mux_poll_task *poll_task; 133 struct p9_client *client;
175 int msize;
176 unsigned char extended;
177 struct p9_trans *trans;
178 struct p9_idpool *tagpool;
179 int err; 134 int err;
180 struct list_head req_list; 135 struct list_head req_list;
181 struct list_head unsent_req_list; 136 struct list_head unsent_req_list;
182 struct p9_fcall *rcall; 137 struct p9_req_t *req;
138 char tmp_buf[7];
139 int rsize;
183 int rpos; 140 int rpos;
184 char *rbuf; 141 char *rbuf;
185 int wpos; 142 int wpos;
186 int wsize; 143 int wsize;
187 char *wbuf; 144 char *wbuf;
188 wait_queue_t poll_wait[MAXPOLLWADDR]; 145 struct list_head poll_pending_link;
189 wait_queue_head_t *poll_waddr[MAXPOLLWADDR]; 146 struct p9_poll_wait poll_wait[MAXPOLLWADDR];
190 poll_table pt; 147 poll_table pt;
191 struct work_struct rq; 148 struct work_struct rq;
192 struct work_struct wq; 149 struct work_struct wq;
193 unsigned long wsched; 150 unsigned long wsched;
194}; 151};
195 152
196/** 153static DEFINE_SPINLOCK(p9_poll_lock);
197 * struct p9_mux_rpc - fd mux rpc accounting structure 154static LIST_HEAD(p9_poll_pending_list);
198 * @m: connection this request was issued on
199 * @err: error state
200 * @tcall: request &p9_fcall
201 * @rcall: response &p9_fcall
202 * @wqueue: wait queue that client is blocked on for this rpc
203 *
204 * Bug: isn't this information duplicated elsewhere like &p9_req
205 */
206
207struct p9_mux_rpc {
208 struct p9_conn *m;
209 int err;
210 struct p9_fcall *tcall;
211 struct p9_fcall *rcall;
212 wait_queue_head_t wqueue;
213};
214
215static int p9_poll_proc(void *);
216static void p9_read_work(struct work_struct *work);
217static void p9_write_work(struct work_struct *work);
218static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
219 poll_table *p);
220static int p9_fd_write(struct p9_trans *trans, void *v, int len);
221static int p9_fd_read(struct p9_trans *trans, void *v, int len);
222
223static DEFINE_MUTEX(p9_mux_task_lock);
224static struct workqueue_struct *p9_mux_wq; 155static struct workqueue_struct *p9_mux_wq;
156static struct task_struct *p9_poll_task;
225 157
226static int p9_mux_num; 158static void p9_mux_poll_stop(struct p9_conn *m)
227static int p9_mux_poll_task_num;
228static struct p9_mux_poll_task p9_mux_poll_tasks[100];
229
230static void p9_conn_destroy(struct p9_conn *);
231static unsigned int p9_fd_poll(struct p9_trans *trans,
232 struct poll_table_struct *pt);
233
234#ifdef P9_NONBLOCK
235static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
236 p9_conn_req_callback cb, void *a);
237#endif /* P9_NONBLOCK */
238
239static void p9_conn_cancel(struct p9_conn *m, int err);
240
241static u16 p9_mux_get_tag(struct p9_conn *m)
242{ 159{
243 int tag; 160 unsigned long flags;
161 int i;
244 162
245 tag = p9_idpool_get(m->tagpool); 163 for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
246 if (tag < 0) 164 struct p9_poll_wait *pwait = &m->poll_wait[i];
247 return P9_NOTAG;
248 else
249 return (u16) tag;
250}
251 165
252static void p9_mux_put_tag(struct p9_conn *m, u16 tag) 166 if (pwait->wait_addr) {
253{ 167 remove_wait_queue(pwait->wait_addr, &pwait->wait);
254 if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool)) 168 pwait->wait_addr = NULL;
255 p9_idpool_put(tag, m->tagpool); 169 }
170 }
171
172 spin_lock_irqsave(&p9_poll_lock, flags);
173 list_del_init(&m->poll_pending_link);
174 spin_unlock_irqrestore(&p9_poll_lock, flags);
256} 175}
257 176
258/** 177/**
259 * p9_mux_calc_poll_procs - calculates the number of polling procs 178 * p9_conn_cancel - cancel all pending requests with error
260 * @muxnum: number of mounts 179 * @m: mux data
180 * @err: error code
261 * 181 *
262 * Calculation is based on the number of mounted v9fs filesystems.
263 * The current implementation returns sqrt of the number of mounts.
264 */ 182 */
265 183
266static int p9_mux_calc_poll_procs(int muxnum) 184static void p9_conn_cancel(struct p9_conn *m, int err)
267{ 185{
268 int n; 186 struct p9_req_t *req, *rtmp;
269 187 unsigned long flags;
270 if (p9_mux_poll_task_num) 188 LIST_HEAD(cancel_list);
271 n = muxnum / p9_mux_poll_task_num +
272 (muxnum % p9_mux_poll_task_num ? 1 : 0);
273 else
274 n = 1;
275
276 if (n > ARRAY_SIZE(p9_mux_poll_tasks))
277 n = ARRAY_SIZE(p9_mux_poll_tasks);
278
279 return n;
280}
281 189
282static int p9_mux_poll_start(struct p9_conn *m) 190 P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
283{
284 int i, n;
285 struct p9_mux_poll_task *vpt, *vptlast;
286 struct task_struct *pproc;
287
288 P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num,
289 p9_mux_poll_task_num);
290 mutex_lock(&p9_mux_task_lock);
291
292 n = p9_mux_calc_poll_procs(p9_mux_num + 1);
293 if (n > p9_mux_poll_task_num) {
294 for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
295 if (p9_mux_poll_tasks[i].task == NULL) {
296 vpt = &p9_mux_poll_tasks[i];
297 P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n",
298 vpt);
299 pproc = kthread_create(p9_poll_proc, vpt,
300 "v9fs-poll");
301
302 if (!IS_ERR(pproc)) {
303 vpt->task = pproc;
304 INIT_LIST_HEAD(&vpt->mux_list);
305 vpt->muxnum = 0;
306 p9_mux_poll_task_num++;
307 wake_up_process(vpt->task);
308 }
309 break;
310 }
311 }
312 191
313 if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) 192 spin_lock_irqsave(&m->client->lock, flags);
314 P9_DPRINTK(P9_DEBUG_ERROR,
315 "warning: no free poll slots\n");
316 }
317 193
318 n = (p9_mux_num + 1) / p9_mux_poll_task_num + 194 if (m->err) {
319 ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0); 195 spin_unlock_irqrestore(&m->client->lock, flags);
320 196 return;
321 vptlast = NULL;
322 for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
323 vpt = &p9_mux_poll_tasks[i];
324 if (vpt->task != NULL) {
325 vptlast = vpt;
326 if (vpt->muxnum < n) {
327 P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
328 list_add(&m->mux_list, &vpt->mux_list);
329 vpt->muxnum++;
330 m->poll_task = vpt;
331 memset(&m->poll_waddr, 0,
332 sizeof(m->poll_waddr));
333 init_poll_funcptr(&m->pt, p9_pollwait);
334 break;
335 }
336 }
337 } 197 }
338 198
339 if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) { 199 m->err = err;
340 if (vptlast == NULL) {
341 mutex_unlock(&p9_mux_task_lock);
342 return -ENOMEM;
343 }
344 200
345 P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i); 201 list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
346 list_add(&m->mux_list, &vptlast->mux_list); 202 req->status = REQ_STATUS_ERROR;
347 vptlast->muxnum++; 203 if (!req->t_err)
348 m->poll_task = vptlast; 204 req->t_err = err;
349 memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); 205 list_move(&req->req_list, &cancel_list);
350 init_poll_funcptr(&m->pt, p9_pollwait);
351 } 206 }
352 207 list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
353 p9_mux_num++; 208 req->status = REQ_STATUS_ERROR;
354 mutex_unlock(&p9_mux_task_lock); 209 if (!req->t_err)
355 210 req->t_err = err;
356 return 0; 211 list_move(&req->req_list, &cancel_list);
357}
358
359static void p9_mux_poll_stop(struct p9_conn *m)
360{
361 int i;
362 struct p9_mux_poll_task *vpt;
363
364 mutex_lock(&p9_mux_task_lock);
365 vpt = m->poll_task;
366 list_del(&m->mux_list);
367 for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
368 if (m->poll_waddr[i] != NULL) {
369 remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
370 m->poll_waddr[i] = NULL;
371 }
372 } 212 }
373 vpt->muxnum--; 213 spin_unlock_irqrestore(&m->client->lock, flags);
374 if (!vpt->muxnum) { 214
375 P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt); 215 list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
376 kthread_stop(vpt->task); 216 list_del(&req->req_list);
377 vpt->task = NULL; 217 P9_DPRINTK(P9_DEBUG_ERROR, "call back req %p\n", req);
378 p9_mux_poll_task_num--; 218 p9_client_cb(m->client, req);
379 } 219 }
380 p9_mux_num--;
381 mutex_unlock(&p9_mux_task_lock);
382} 220}
383 221
384/** 222static unsigned int
385 * p9_conn_create - allocate and initialize the per-session mux data 223p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt)
386 * @trans: transport structure
387 *
388 * Note: Creates the polling task if this is the first session.
389 */
390
391static struct p9_conn *p9_conn_create(struct p9_trans *trans)
392{ 224{
393 int i, n; 225 int ret, n;
394 struct p9_conn *m; 226 struct p9_trans_fd *ts = NULL;
395 227
396 P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, 228 if (client && client->status == Connected)
397 trans->msize); 229 ts = client->trans;
398 m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL);
399 if (!m)
400 return ERR_PTR(-ENOMEM);
401 230
402 spin_lock_init(&m->lock); 231 if (!ts)
403 INIT_LIST_HEAD(&m->mux_list); 232 return -EREMOTEIO;
404 m->msize = trans->msize;
405 m->extended = trans->extended;
406 m->trans = trans;
407 m->tagpool = p9_idpool_create();
408 if (IS_ERR(m->tagpool)) {
409 kfree(m);
410 return ERR_PTR(-ENOMEM);
411 }
412 233
413 INIT_LIST_HEAD(&m->req_list); 234 if (!ts->rd->f_op || !ts->rd->f_op->poll)
414 INIT_LIST_HEAD(&m->unsent_req_list); 235 return -EIO;
415 INIT_WORK(&m->rq, p9_read_work);
416 INIT_WORK(&m->wq, p9_write_work);
417 n = p9_mux_poll_start(m);
418 if (n) {
419 kfree(m);
420 return ERR_PTR(n);
421 }
422 236
423 n = p9_fd_poll(trans, &m->pt); 237 if (!ts->wr->f_op || !ts->wr->f_op->poll)
424 if (n & POLLIN) { 238 return -EIO;
425 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
426 set_bit(Rpending, &m->wsched);
427 }
428 239
429 if (n & POLLOUT) { 240 ret = ts->rd->f_op->poll(ts->rd, pt);
430 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); 241 if (ret < 0)
431 set_bit(Wpending, &m->wsched); 242 return ret;
432 }
433 243
434 for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { 244 if (ts->rd != ts->wr) {
435 if (IS_ERR(m->poll_waddr[i])) { 245 n = ts->wr->f_op->poll(ts->wr, pt);
436 p9_mux_poll_stop(m); 246 if (n < 0)
437 kfree(m); 247 return n;
438 return (void *)m->poll_waddr; /* the error code */ 248 ret = (ret & ~POLLOUT) | (n & ~POLLIN);
439 }
440 } 249 }
441 250
442 return m; 251 return ret;
443} 252}
444 253
445/** 254/**
446 * p9_mux_destroy - cancels all pending requests and frees mux resources 255 * p9_fd_read- read from a fd
447 * @m: mux to destroy 256 * @client: client instance
257 * @v: buffer to receive data into
258 * @len: size of receive buffer
448 * 259 *
449 */ 260 */
450 261
451static void p9_conn_destroy(struct p9_conn *m) 262static int p9_fd_read(struct p9_client *client, void *v, int len)
452{ 263{
453 P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, 264 int ret;
454 m->mux_list.prev, m->mux_list.next); 265 struct p9_trans_fd *ts = NULL;
455 266
456 p9_mux_poll_stop(m); 267 if (client && client->status != Disconnected)
457 cancel_work_sync(&m->rq); 268 ts = client->trans;
458 cancel_work_sync(&m->wq);
459 269
460 p9_conn_cancel(m, -ECONNRESET); 270 if (!ts)
271 return -EREMOTEIO;
461 272
462 m->trans = NULL; 273 if (!(ts->rd->f_flags & O_NONBLOCK))
463 p9_idpool_destroy(m->tagpool); 274 P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
464 kfree(m); 275
276 ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
277 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
278 client->status = Disconnected;
279 return ret;
465} 280}
466 281
467/** 282/**
468 * p9_pollwait - add poll task to the wait queue 283 * p9_read_work - called when there is some data to be read from a transport
469 * @filp: file pointer being polled 284 * @work: container of work to be done
470 * @wait_address: wait_q to block on
471 * @p: poll state
472 * 285 *
473 * called by files poll operation to add v9fs-poll task to files wait queue
474 */ 286 */
475 287
476static void 288static void p9_read_work(struct work_struct *work)
477p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
478{ 289{
479 int i; 290 int n, err;
480 struct p9_conn *m; 291 struct p9_conn *m;
481 292
482 m = container_of(p, struct p9_conn, pt); 293 m = container_of(work, struct p9_conn, rq);
483 for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
484 if (m->poll_waddr[i] == NULL)
485 break;
486 294
487 if (i >= ARRAY_SIZE(m->poll_waddr)) { 295 if (m->err < 0)
488 P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
489 return; 296 return;
490 }
491 297
492 m->poll_waddr[i] = wait_address; 298 P9_DPRINTK(P9_DEBUG_TRANS, "start mux %p pos %d\n", m, m->rpos);
493 299
494 if (!wait_address) { 300 if (!m->rbuf) {
495 P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); 301 m->rbuf = m->tmp_buf;
496 m->poll_waddr[i] = ERR_PTR(-EIO); 302 m->rpos = 0;
303 m->rsize = 7; /* start by reading header */
304 }
305
306 clear_bit(Rpending, &m->wsched);
307 P9_DPRINTK(P9_DEBUG_TRANS, "read mux %p pos %d size: %d = %d\n", m,
308 m->rpos, m->rsize, m->rsize-m->rpos);
309 err = p9_fd_read(m->client, m->rbuf + m->rpos,
310 m->rsize - m->rpos);
311 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err);
312 if (err == -EAGAIN) {
313 clear_bit(Rworksched, &m->wsched);
497 return; 314 return;
498 } 315 }
499 316
500 init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task); 317 if (err <= 0)
501 add_wait_queue(wait_address, &m->poll_wait[i]); 318 goto error;
502}
503 319
504/** 320 m->rpos += err;
505 * p9_poll_mux - polls a mux and schedules read or write works if necessary
506 * @m: connection to poll
507 *
508 */
509 321
510static void p9_poll_mux(struct p9_conn *m) 322 if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */
511{ 323 u16 tag;
512 int n; 324 P9_DPRINTK(P9_DEBUG_TRANS, "got new header\n");
513 325
514 if (m->err < 0) 326 n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */
515 return; 327 if (n >= m->client->msize) {
328 P9_DPRINTK(P9_DEBUG_ERROR,
329 "requested packet size too big: %d\n", n);
330 err = -EIO;
331 goto error;
332 }
516 333
517 n = p9_fd_poll(m->trans, NULL); 334 tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */
518 if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { 335 P9_DPRINTK(P9_DEBUG_TRANS,
519 P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n); 336 "mux %p pkt: size: %d bytes tag: %d\n", m, n, tag);
520 if (n >= 0)
521 n = -ECONNRESET;
522 p9_conn_cancel(m, n);
523 }
524 337
525 if (n & POLLIN) { 338 m->req = p9_tag_lookup(m->client, tag);
526 set_bit(Rpending, &m->wsched); 339 if (!m->req) {
527 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); 340 P9_DPRINTK(P9_DEBUG_ERROR, "Unexpected packet tag %d\n",
528 if (!test_and_set_bit(Rworksched, &m->wsched)) { 341 tag);
529 P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); 342 err = -EIO;
530 queue_work(p9_mux_wq, &m->rq); 343 goto error;
531 } 344 }
532 }
533 345
534 if (n & POLLOUT) { 346 if (m->req->rc == NULL) {
535 set_bit(Wpending, &m->wsched); 347 m->req->rc = kmalloc(sizeof(struct p9_fcall) +
536 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); 348 m->client->msize, GFP_KERNEL);
537 if ((m->wsize || !list_empty(&m->unsent_req_list)) 349 if (!m->req->rc) {
538 && !test_and_set_bit(Wworksched, &m->wsched)) { 350 m->req = NULL;
539 P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); 351 err = -ENOMEM;
540 queue_work(p9_mux_wq, &m->wq); 352 goto error;
353 }
541 } 354 }
355 m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall);
356 memcpy(m->rbuf, m->tmp_buf, m->rsize);
357 m->rsize = n;
542 } 358 }
359
360 /* not an else because some packets (like clunk) have no payload */
361 if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */
362 P9_DPRINTK(P9_DEBUG_TRANS, "got new packet\n");
363 spin_lock(&m->client->lock);
364 list_del(&m->req->req_list);
365 spin_unlock(&m->client->lock);
366 p9_client_cb(m->client, m->req);
367
368 m->rbuf = NULL;
369 m->rpos = 0;
370 m->rsize = 0;
371 m->req = NULL;
372 }
373
374 if (!list_empty(&m->req_list)) {
375 if (test_and_clear_bit(Rpending, &m->wsched))
376 n = POLLIN;
377 else
378 n = p9_fd_poll(m->client, NULL);
379
380 if (n & POLLIN) {
381 P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m);
382 queue_work(p9_mux_wq, &m->rq);
383 } else
384 clear_bit(Rworksched, &m->wsched);
385 } else
386 clear_bit(Rworksched, &m->wsched);
387
388 return;
389error:
390 p9_conn_cancel(m, err);
391 clear_bit(Rworksched, &m->wsched);
543} 392}
544 393
545/** 394/**
546 * p9_poll_proc - poll worker thread 395 * p9_fd_write - write to a socket
547 * @a: thread state and arguments 396 * @client: client instance
548 * 397 * @v: buffer to send data from
549 * polls all v9fs transports for new events and queues the appropriate 398 * @len: size of send buffer
550 * work to the work queue
551 * 399 *
552 */ 400 */
553 401
554static int p9_poll_proc(void *a) 402static int p9_fd_write(struct p9_client *client, void *v, int len)
555{ 403{
556 struct p9_conn *m, *mtmp; 404 int ret;
557 struct p9_mux_poll_task *vpt; 405 mm_segment_t oldfs;
406 struct p9_trans_fd *ts = NULL;
558 407
559 vpt = a; 408 if (client && client->status != Disconnected)
560 P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt); 409 ts = client->trans;
561 while (!kthread_should_stop()) {
562 set_current_state(TASK_INTERRUPTIBLE);
563 410
564 list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) { 411 if (!ts)
565 p9_poll_mux(m); 412 return -EREMOTEIO;
566 }
567 413
568 P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); 414 if (!(ts->wr->f_flags & O_NONBLOCK))
569 schedule_timeout(SCHED_TIMEOUT * HZ); 415 P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
570 }
571 416
572 __set_current_state(TASK_RUNNING); 417 oldfs = get_fs();
573 P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); 418 set_fs(get_ds());
574 return 0; 419 /* The cast to a user pointer is valid due to the set_fs() */
420 ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
421 set_fs(oldfs);
422
423 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
424 client->status = Disconnected;
425 return ret;
575} 426}
576 427
577/** 428/**
@@ -584,7 +435,7 @@ static void p9_write_work(struct work_struct *work)
584{ 435{
585 int n, err; 436 int n, err;
586 struct p9_conn *m; 437 struct p9_conn *m;
587 struct p9_req *req; 438 struct p9_req_t *req;
588 439
589 m = container_of(work, struct p9_conn, wq); 440 m = container_of(work, struct p9_conn, wq);
590 441
@@ -599,25 +450,23 @@ static void p9_write_work(struct work_struct *work)
599 return; 450 return;
600 } 451 }
601 452
602 spin_lock(&m->lock); 453 spin_lock(&m->client->lock);
603again: 454 req = list_entry(m->unsent_req_list.next, struct p9_req_t,
604 req = list_entry(m->unsent_req_list.next, struct p9_req,
605 req_list); 455 req_list);
456 req->status = REQ_STATUS_SENT;
606 list_move_tail(&req->req_list, &m->req_list); 457 list_move_tail(&req->req_list, &m->req_list);
607 if (req->err == ERREQFLUSH)
608 goto again;
609 458
610 m->wbuf = req->tcall->sdata; 459 m->wbuf = req->tc->sdata;
611 m->wsize = req->tcall->size; 460 m->wsize = req->tc->size;
612 m->wpos = 0; 461 m->wpos = 0;
613 spin_unlock(&m->lock); 462 spin_unlock(&m->client->lock);
614 } 463 }
615 464
616 P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, 465 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p pos %d size %d\n", m, m->wpos,
617 m->wsize); 466 m->wsize);
618 clear_bit(Wpending, &m->wsched); 467 clear_bit(Wpending, &m->wsched);
619 err = p9_fd_write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos); 468 err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos);
620 P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err); 469 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err);
621 if (err == -EAGAIN) { 470 if (err == -EAGAIN) {
622 clear_bit(Wworksched, &m->wsched); 471 clear_bit(Wworksched, &m->wsched);
623 return; 472 return;
@@ -638,10 +487,10 @@ again:
638 if (test_and_clear_bit(Wpending, &m->wsched)) 487 if (test_and_clear_bit(Wpending, &m->wsched))
639 n = POLLOUT; 488 n = POLLOUT;
640 else 489 else
641 n = p9_fd_poll(m->trans, NULL); 490 n = p9_fd_poll(m->client, NULL);
642 491
643 if (n & POLLOUT) { 492 if (n & POLLOUT) {
644 P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); 493 P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m);
645 queue_work(p9_mux_wq, &m->wq); 494 queue_work(p9_mux_wq, &m->wq);
646 } else 495 } else
647 clear_bit(Wworksched, &m->wsched); 496 clear_bit(Wworksched, &m->wsched);
@@ -655,504 +504,197 @@ error:
655 clear_bit(Wworksched, &m->wsched); 504 clear_bit(Wworksched, &m->wsched);
656} 505}
657 506
658static void process_request(struct p9_conn *m, struct p9_req *req) 507static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
659{ 508{
660 int ecode; 509 struct p9_poll_wait *pwait =
661 struct p9_str *ename; 510 container_of(wait, struct p9_poll_wait, wait);
662 511 struct p9_conn *m = pwait->conn;
663 if (!req->err && req->rcall->id == P9_RERROR) { 512 unsigned long flags;
664 ecode = req->rcall->params.rerror.errno; 513 DECLARE_WAITQUEUE(dummy_wait, p9_poll_task);
665 ename = &req->rcall->params.rerror.error;
666
667 P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
668 ename->str);
669
670 if (m->extended)
671 req->err = -ecode;
672 514
673 if (!req->err) { 515 spin_lock_irqsave(&p9_poll_lock, flags);
674 req->err = p9_errstr2errno(ename->str, ename->len); 516 if (list_empty(&m->poll_pending_link))
517 list_add_tail(&m->poll_pending_link, &p9_poll_pending_list);
518 spin_unlock_irqrestore(&p9_poll_lock, flags);
675 519
676 /* string match failed */ 520 /* perform the default wake up operation */
677 if (!req->err) { 521 return default_wake_function(&dummy_wait, mode, sync, key);
678 PRINT_FCALL_ERROR("unknown error", req->rcall);
679 req->err = -ESERVERFAULT;
680 }
681 }
682 } else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
683 P9_DPRINTK(P9_DEBUG_ERROR,
684 "fcall mismatch: expected %d, got %d\n",
685 req->tcall->id + 1, req->rcall->id);
686 if (!req->err)
687 req->err = -EIO;
688 }
689} 522}
690 523
691/** 524/**
692 * p9_read_work - called when there is some data to be read from a transport 525 * p9_pollwait - add poll task to the wait queue
693 * @work: container of work to be done 526 * @filp: file pointer being polled
527 * @wait_address: wait_q to block on
528 * @p: poll state
694 * 529 *
530 * called by files poll operation to add v9fs-poll task to files wait queue
695 */ 531 */
696 532
697static void p9_read_work(struct work_struct *work) 533static void
534p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
698{ 535{
699 int n, err; 536 struct p9_conn *m = container_of(p, struct p9_conn, pt);
700 struct p9_conn *m; 537 struct p9_poll_wait *pwait = NULL;
701 struct p9_req *req, *rptr, *rreq; 538 int i;
702 struct p9_fcall *rcall;
703 char *rbuf;
704
705 m = container_of(work, struct p9_conn, rq);
706
707 if (m->err < 0)
708 return;
709
710 rcall = NULL;
711 P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
712 539
713 if (!m->rcall) { 540 for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
714 m->rcall = 541 if (m->poll_wait[i].wait_addr == NULL) {
715 kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL); 542 pwait = &m->poll_wait[i];
716 if (!m->rcall) { 543 break;
717 err = -ENOMEM;
718 goto error;
719 } 544 }
720
721 m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
722 m->rpos = 0;
723 } 545 }
724 546
725 clear_bit(Rpending, &m->wsched); 547 if (!pwait) {
726 err = p9_fd_read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); 548 P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
727 P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
728 if (err == -EAGAIN) {
729 clear_bit(Rworksched, &m->wsched);
730 return; 549 return;
731 } 550 }
732 551
733 if (err <= 0) 552 pwait->conn = m;
734 goto error; 553 pwait->wait_addr = wait_address;
735 554 init_waitqueue_func_entry(&pwait->wait, p9_pollwake);
736 m->rpos += err; 555 add_wait_queue(wait_address, &pwait->wait);
737 while (m->rpos > 4) {
738 n = le32_to_cpu(*(__le32 *) m->rbuf);
739 if (n >= m->msize) {
740 P9_DPRINTK(P9_DEBUG_ERROR,
741 "requested packet size too big: %d\n", n);
742 err = -EIO;
743 goto error;
744 }
745
746 if (m->rpos < n)
747 break;
748
749 err =
750 p9_deserialize_fcall(m->rbuf, n, m->rcall, m->extended);
751 if (err < 0)
752 goto error;
753
754#ifdef CONFIG_NET_9P_DEBUG
755 if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
756 char buf[150];
757
758 p9_printfcall(buf, sizeof(buf), m->rcall,
759 m->extended);
760 printk(KERN_NOTICE ">>> %p %s\n", m, buf);
761 }
762#endif
763
764 rcall = m->rcall;
765 rbuf = m->rbuf;
766 if (m->rpos > n) {
767 m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,
768 GFP_KERNEL);
769 if (!m->rcall) {
770 err = -ENOMEM;
771 goto error;
772 }
773
774 m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
775 memmove(m->rbuf, rbuf + n, m->rpos - n);
776 m->rpos -= n;
777 } else {
778 m->rcall = NULL;
779 m->rbuf = NULL;
780 m->rpos = 0;
781 }
782
783 P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
784 rcall->id, rcall->tag);
785
786 req = NULL;
787 spin_lock(&m->lock);
788 list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
789 if (rreq->tag == rcall->tag) {
790 req = rreq;
791 if (req->flush != Flushing)
792 list_del(&req->req_list);
793 break;
794 }
795 }
796 spin_unlock(&m->lock);
797
798 if (req) {
799 req->rcall = rcall;
800 process_request(m, req);
801
802 if (req->flush != Flushing) {
803 if (req->cb)
804 (*req->cb) (req, req->cba);
805 else
806 kfree(req->rcall);
807 }
808 } else {
809 if (err >= 0 && rcall->id != P9_RFLUSH)
810 P9_DPRINTK(P9_DEBUG_ERROR,
811 "unexpected response mux %p id %d tag %d\n",
812 m, rcall->id, rcall->tag);
813 kfree(rcall);
814 }
815 }
816
817 if (!list_empty(&m->req_list)) {
818 if (test_and_clear_bit(Rpending, &m->wsched))
819 n = POLLIN;
820 else
821 n = p9_fd_poll(m->trans, NULL);
822
823 if (n & POLLIN) {
824 P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
825 queue_work(p9_mux_wq, &m->rq);
826 } else
827 clear_bit(Rworksched, &m->wsched);
828 } else
829 clear_bit(Rworksched, &m->wsched);
830
831 return;
832
833error:
834 p9_conn_cancel(m, err);
835 clear_bit(Rworksched, &m->wsched);
836} 556}
837 557
838/** 558/**
839 * p9_send_request - send 9P request 559 * p9_conn_create - allocate and initialize the per-session mux data
840 * The function can sleep until the request is scheduled for sending. 560 * @client: client instance
841 * The function can be interrupted. Return from the function is not
842 * a guarantee that the request is sent successfully. Can return errors
843 * that can be retrieved by PTR_ERR macros.
844 *
845 * @m: mux data
846 * @tc: request to be sent
847 * @cb: callback function to call when response is received
848 * @cba: parameter to pass to the callback function
849 * 561 *
562 * Note: Creates the polling task if this is the first session.
850 */ 563 */
851 564
852static struct p9_req *p9_send_request(struct p9_conn *m, 565static struct p9_conn *p9_conn_create(struct p9_client *client)
853 struct p9_fcall *tc,
854 p9_conn_req_callback cb, void *cba)
855{ 566{
856 int n; 567 int n;
857 struct p9_req *req; 568 struct p9_conn *m;
858
859 P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
860 tc, tc->id);
861 if (m->err < 0)
862 return ERR_PTR(m->err);
863
864 req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);
865 if (!req)
866 return ERR_PTR(-ENOMEM);
867
868 if (tc->id == P9_TVERSION)
869 n = P9_NOTAG;
870 else
871 n = p9_mux_get_tag(m);
872 569
873 if (n < 0) { 570 P9_DPRINTK(P9_DEBUG_TRANS, "client %p msize %d\n", client,
874 kfree(req); 571 client->msize);
572 m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL);
573 if (!m)
875 return ERR_PTR(-ENOMEM); 574 return ERR_PTR(-ENOMEM);
876 }
877 575
878 p9_set_tag(tc, n); 576 INIT_LIST_HEAD(&m->mux_list);
577 m->client = client;
879 578
880#ifdef CONFIG_NET_9P_DEBUG 579 INIT_LIST_HEAD(&m->req_list);
881 if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { 580 INIT_LIST_HEAD(&m->unsent_req_list);
882 char buf[150]; 581 INIT_WORK(&m->rq, p9_read_work);
582 INIT_WORK(&m->wq, p9_write_work);
583 INIT_LIST_HEAD(&m->poll_pending_link);
584 init_poll_funcptr(&m->pt, p9_pollwait);
883 585
884 p9_printfcall(buf, sizeof(buf), tc, m->extended); 586 n = p9_fd_poll(client, &m->pt);
885 printk(KERN_NOTICE "<<< %p %s\n", m, buf); 587 if (n & POLLIN) {
588 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m);
589 set_bit(Rpending, &m->wsched);
886 } 590 }
887#endif
888
889 spin_lock_init(&req->lock);
890 req->tag = n;
891 req->tcall = tc;
892 req->rcall = NULL;
893 req->err = 0;
894 req->cb = cb;
895 req->cba = cba;
896 req->flush = None;
897
898 spin_lock(&m->lock);
899 list_add_tail(&req->req_list, &m->unsent_req_list);
900 spin_unlock(&m->lock);
901
902 if (test_and_clear_bit(Wpending, &m->wsched))
903 n = POLLOUT;
904 else
905 n = p9_fd_poll(m->trans, NULL);
906 591
907 if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) 592 if (n & POLLOUT) {
908 queue_work(p9_mux_wq, &m->wq); 593 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m);
594 set_bit(Wpending, &m->wsched);
595 }
909 596
910 return req; 597 return m;
911} 598}
912 599
913static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req) 600/**
914{ 601 * p9_poll_mux - polls a mux and schedules read or write works if necessary
915 p9_mux_put_tag(m, req->tag); 602 * @m: connection to poll
916 kfree(req); 603 *
917} 604 */
918 605
919static void p9_mux_flush_cb(struct p9_req *freq, void *a) 606static void p9_poll_mux(struct p9_conn *m)
920{ 607{
921 int tag; 608 int n;
922 struct p9_conn *m;
923 struct p9_req *req, *rreq, *rptr;
924
925 m = a;
926 P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
927 freq->tcall, freq->rcall, freq->err,
928 freq->tcall->params.tflush.oldtag);
929
930 spin_lock(&m->lock);
931 tag = freq->tcall->params.tflush.oldtag;
932 req = NULL;
933 list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
934 if (rreq->tag == tag) {
935 req = rreq;
936 list_del(&req->req_list);
937 break;
938 }
939 }
940 spin_unlock(&m->lock);
941 609
942 if (req) { 610 if (m->err < 0)
943 spin_lock(&req->lock); 611 return;
944 req->flush = Flushed;
945 spin_unlock(&req->lock);
946 612
947 if (req->cb) 613 n = p9_fd_poll(m->client, NULL);
948 (*req->cb) (req, req->cba); 614 if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
949 else 615 P9_DPRINTK(P9_DEBUG_TRANS, "error mux %p err %d\n", m, n);
950 kfree(req->rcall); 616 if (n >= 0)
617 n = -ECONNRESET;
618 p9_conn_cancel(m, n);
951 } 619 }
952 620
953 kfree(freq->tcall); 621 if (n & POLLIN) {
954 kfree(freq->rcall); 622 set_bit(Rpending, &m->wsched);
955 p9_mux_free_request(m, freq); 623 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m);
956} 624 if (!test_and_set_bit(Rworksched, &m->wsched)) {
957 625 P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m);
958static int 626 queue_work(p9_mux_wq, &m->rq);
959p9_mux_flush_request(struct p9_conn *m, struct p9_req *req) 627 }
960{
961 struct p9_fcall *fc;
962 struct p9_req *rreq, *rptr;
963
964 P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
965
966 /* if a response was received for a request, do nothing */
967 spin_lock(&req->lock);
968 if (req->rcall || req->err) {
969 spin_unlock(&req->lock);
970 P9_DPRINTK(P9_DEBUG_MUX,
971 "mux %p req %p response already received\n", m, req);
972 return 0;
973 } 628 }
974 629
975 req->flush = Flushing; 630 if (n & POLLOUT) {
976 spin_unlock(&req->lock); 631 set_bit(Wpending, &m->wsched);
977 632 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m);
978 spin_lock(&m->lock); 633 if ((m->wsize || !list_empty(&m->unsent_req_list))
979 /* if the request is not sent yet, just remove it from the list */ 634 && !test_and_set_bit(Wworksched, &m->wsched)) {
980 list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) { 635 P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m);
981 if (rreq->tag == req->tag) { 636 queue_work(p9_mux_wq, &m->wq);
982 P9_DPRINTK(P9_DEBUG_MUX,
983 "mux %p req %p request is not sent yet\n", m, req);
984 list_del(&rreq->req_list);
985 req->flush = Flushed;
986 spin_unlock(&m->lock);
987 if (req->cb)
988 (*req->cb) (req, req->cba);
989 return 0;
990 } 637 }
991 } 638 }
992 spin_unlock(&m->lock);
993
994 clear_thread_flag(TIF_SIGPENDING);
995 fc = p9_create_tflush(req->tag);
996 p9_send_request(m, fc, p9_mux_flush_cb, m);
997 return 1;
998}
999
1000static void
1001p9_conn_rpc_cb(struct p9_req *req, void *a)
1002{
1003 struct p9_mux_rpc *r;
1004
1005 P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);
1006 r = a;
1007 r->rcall = req->rcall;
1008 r->err = req->err;
1009
1010 if (req->flush != None && !req->err)
1011 r->err = -ERESTARTSYS;
1012
1013 wake_up(&r->wqueue);
1014} 639}
1015 640
1016/** 641/**
1017 * p9_fd_rpc- sends 9P request and waits until a response is available. 642 * p9_fd_request - send 9P request
1018 * The function can be interrupted. 643 * The function can sleep until the request is scheduled for sending.
1019 * @t: transport data 644 * The function can be interrupted. Return from the function is not
1020 * @tc: request to be sent 645 * a guarantee that the request is sent successfully.
1021 * @rc: pointer where a pointer to the response is stored 646 *
647 * @client: client instance
648 * @req: request to be sent
1022 * 649 *
1023 */ 650 */
1024 651
1025int 652static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
1026p9_fd_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc)
1027{ 653{
1028 struct p9_trans_fd *p = t->priv; 654 int n;
1029 struct p9_conn *m = p->conn; 655 struct p9_trans_fd *ts = client->trans;
1030 int err, sigpending; 656 struct p9_conn *m = ts->conn;
1031 unsigned long flags;
1032 struct p9_req *req;
1033 struct p9_mux_rpc r;
1034
1035 r.err = 0;
1036 r.tcall = tc;
1037 r.rcall = NULL;
1038 r.m = m;
1039 init_waitqueue_head(&r.wqueue);
1040
1041 if (rc)
1042 *rc = NULL;
1043
1044 sigpending = 0;
1045 if (signal_pending(current)) {
1046 sigpending = 1;
1047 clear_thread_flag(TIF_SIGPENDING);
1048 }
1049
1050 req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);
1051 if (IS_ERR(req)) {
1052 err = PTR_ERR(req);
1053 P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
1054 return err;
1055 }
1056 657
1057 err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0); 658 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n", m,
1058 if (r.err < 0) 659 current, req->tc, req->tc->id);
1059 err = r.err; 660 if (m->err < 0)
1060 661 return m->err;
1061 if (err == -ERESTARTSYS && m->trans->status == Connected
1062 && m->err == 0) {
1063 if (p9_mux_flush_request(m, req)) {
1064 /* wait until we get response of the flush message */
1065 do {
1066 clear_thread_flag(TIF_SIGPENDING);
1067 err = wait_event_interruptible(r.wqueue,
1068 r.rcall || r.err);
1069 } while (!r.rcall && !r.err && err == -ERESTARTSYS &&
1070 m->trans->status == Connected && !m->err);
1071
1072 err = -ERESTARTSYS;
1073 }
1074 sigpending = 1;
1075 }
1076 662
1077 if (sigpending) { 663 spin_lock(&client->lock);
1078 spin_lock_irqsave(&current->sighand->siglock, flags); 664 req->status = REQ_STATUS_UNSENT;
1079 recalc_sigpending(); 665 list_add_tail(&req->req_list, &m->unsent_req_list);
1080 spin_unlock_irqrestore(&current->sighand->siglock, flags); 666 spin_unlock(&client->lock);
1081 }
1082 667
1083 if (rc) 668 if (test_and_clear_bit(Wpending, &m->wsched))
1084 *rc = r.rcall; 669 n = POLLOUT;
1085 else 670 else
1086 kfree(r.rcall); 671 n = p9_fd_poll(m->client, NULL);
1087 672
1088 p9_mux_free_request(m, req); 673 if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
1089 if (err > 0) 674 queue_work(p9_mux_wq, &m->wq);
1090 err = -EIO;
1091 675
1092 return err; 676 return 0;
1093} 677}
1094 678
1095#ifdef P9_NONBLOCK 679static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)
1096/**
1097 * p9_conn_rpcnb - sends 9P request without waiting for response.
1098 * @m: mux data
1099 * @tc: request to be sent
1100 * @cb: callback function to be called when response arrives
1101 * @a: value to pass to the callback function
1102 *
1103 */
1104
1105int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
1106 p9_conn_req_callback cb, void *a)
1107{ 680{
1108 int err; 681 struct p9_trans_fd *ts = client->trans;
1109 struct p9_req *req; 682 struct p9_conn *m = ts->conn;
683 int ret = 1;
1110 684
1111 req = p9_send_request(m, tc, cb, a); 685 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p req %p\n", m, req);
1112 if (IS_ERR(req)) {
1113 err = PTR_ERR(req);
1114 P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
1115 return PTR_ERR(req);
1116 }
1117 686
1118 P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag); 687 spin_lock(&client->lock);
1119 return 0; 688 list_del(&req->req_list);
1120}
1121#endif /* P9_NONBLOCK */
1122 689
1123/** 690 if (req->status == REQ_STATUS_UNSENT) {
1124 * p9_conn_cancel - cancel all pending requests with error 691 req->status = REQ_STATUS_FLSHD;
1125 * @m: mux data 692 ret = 0;
1126 * @err: error code
1127 *
1128 */
1129
1130void p9_conn_cancel(struct p9_conn *m, int err)
1131{
1132 struct p9_req *req, *rtmp;
1133 LIST_HEAD(cancel_list);
1134
1135 P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
1136 m->err = err;
1137 spin_lock(&m->lock);
1138 list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
1139 list_move(&req->req_list, &cancel_list);
1140 } 693 }
1141 list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
1142 list_move(&req->req_list, &cancel_list);
1143 }
1144 spin_unlock(&m->lock);
1145 694
1146 list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { 695 spin_unlock(&client->lock);
1147 list_del(&req->req_list);
1148 if (!req->err)
1149 req->err = err;
1150 696
1151 if (req->cb) 697 return ret;
1152 (*req->cb) (req, req->cba);
1153 else
1154 kfree(req->rcall);
1155 }
1156} 698}
1157 699
1158/** 700/**
@@ -1216,7 +758,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
1216 return 0; 758 return 0;
1217} 759}
1218 760
1219static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd) 761static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
1220{ 762{
1221 struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), 763 struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
1222 GFP_KERNEL); 764 GFP_KERNEL);
@@ -1234,13 +776,13 @@ static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd)
1234 return -EIO; 776 return -EIO;
1235 } 777 }
1236 778
1237 trans->priv = ts; 779 client->trans = ts;
1238 trans->status = Connected; 780 client->status = Connected;
1239 781
1240 return 0; 782 return 0;
1241} 783}
1242 784
1243static int p9_socket_open(struct p9_trans *trans, struct socket *csocket) 785static int p9_socket_open(struct p9_client *client, struct socket *csocket)
1244{ 786{
1245 int fd, ret; 787 int fd, ret;
1246 788
@@ -1251,137 +793,65 @@ static int p9_socket_open(struct p9_trans *trans, struct socket *csocket)
1251 return fd; 793 return fd;
1252 } 794 }
1253 795
1254 ret = p9_fd_open(trans, fd, fd); 796 ret = p9_fd_open(client, fd, fd);
1255 if (ret < 0) { 797 if (ret < 0) {
1256 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n"); 798 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
1257 sockfd_put(csocket); 799 sockfd_put(csocket);
1258 return ret; 800 return ret;
1259 } 801 }
1260 802
1261 ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK; 803 ((struct p9_trans_fd *)client->trans)->rd->f_flags |= O_NONBLOCK;
1262 804
1263 return 0; 805 return 0;
1264} 806}
1265 807
1266/** 808/**
1267 * p9_fd_read- read from a fd 809 * p9_mux_destroy - cancels all pending requests and frees mux resources
1268 * @trans: transport instance state 810 * @m: mux to destroy
1269 * @v: buffer to receive data into
1270 * @len: size of receive buffer
1271 *
1272 */
1273
1274static int p9_fd_read(struct p9_trans *trans, void *v, int len)
1275{
1276 int ret;
1277 struct p9_trans_fd *ts = NULL;
1278
1279 if (trans && trans->status != Disconnected)
1280 ts = trans->priv;
1281
1282 if (!ts)
1283 return -EREMOTEIO;
1284
1285 if (!(ts->rd->f_flags & O_NONBLOCK))
1286 P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
1287
1288 ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
1289 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
1290 trans->status = Disconnected;
1291 return ret;
1292}
1293
1294/**
1295 * p9_fd_write - write to a socket
1296 * @trans: transport instance state
1297 * @v: buffer to send data from
1298 * @len: size of send buffer
1299 * 811 *
1300 */ 812 */
1301 813
1302static int p9_fd_write(struct p9_trans *trans, void *v, int len) 814static void p9_conn_destroy(struct p9_conn *m)
1303{
1304 int ret;
1305 mm_segment_t oldfs;
1306 struct p9_trans_fd *ts = NULL;
1307
1308 if (trans && trans->status != Disconnected)
1309 ts = trans->priv;
1310
1311 if (!ts)
1312 return -EREMOTEIO;
1313
1314 if (!(ts->wr->f_flags & O_NONBLOCK))
1315 P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
1316
1317 oldfs = get_fs();
1318 set_fs(get_ds());
1319 /* The cast to a user pointer is valid due to the set_fs() */
1320 ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
1321 set_fs(oldfs);
1322
1323 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
1324 trans->status = Disconnected;
1325 return ret;
1326}
1327
1328static unsigned int
1329p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
1330{ 815{
1331 int ret, n; 816 P9_DPRINTK(P9_DEBUG_TRANS, "mux %p prev %p next %p\n", m,
1332 struct p9_trans_fd *ts = NULL; 817 m->mux_list.prev, m->mux_list.next);
1333
1334 if (trans && trans->status == Connected)
1335 ts = trans->priv;
1336
1337 if (!ts)
1338 return -EREMOTEIO;
1339
1340 if (!ts->rd->f_op || !ts->rd->f_op->poll)
1341 return -EIO;
1342
1343 if (!ts->wr->f_op || !ts->wr->f_op->poll)
1344 return -EIO;
1345 818
1346 ret = ts->rd->f_op->poll(ts->rd, pt); 819 p9_mux_poll_stop(m);
1347 if (ret < 0) 820 cancel_work_sync(&m->rq);
1348 return ret; 821 cancel_work_sync(&m->wq);
1349 822
1350 if (ts->rd != ts->wr) { 823 p9_conn_cancel(m, -ECONNRESET);
1351 n = ts->wr->f_op->poll(ts->wr, pt);
1352 if (n < 0)
1353 return n;
1354 ret = (ret & ~POLLOUT) | (n & ~POLLIN);
1355 }
1356 824
1357 return ret; 825 m->client = NULL;
826 kfree(m);
1358} 827}
1359 828
1360/** 829/**
1361 * p9_fd_close - shutdown socket 830 * p9_fd_close - shutdown file descriptor transport
1362 * @trans: private socket structure 831 * @client: client instance
1363 * 832 *
1364 */ 833 */
1365 834
1366static void p9_fd_close(struct p9_trans *trans) 835static void p9_fd_close(struct p9_client *client)
1367{ 836{
1368 struct p9_trans_fd *ts; 837 struct p9_trans_fd *ts;
1369 838
1370 if (!trans) 839 if (!client)
1371 return; 840 return;
1372 841
1373 ts = xchg(&trans->priv, NULL); 842 ts = client->trans;
1374
1375 if (!ts) 843 if (!ts)
1376 return; 844 return;
1377 845
846 client->status = Disconnected;
847
1378 p9_conn_destroy(ts->conn); 848 p9_conn_destroy(ts->conn);
1379 849
1380 trans->status = Disconnected;
1381 if (ts->rd) 850 if (ts->rd)
1382 fput(ts->rd); 851 fput(ts->rd);
1383 if (ts->wr) 852 if (ts->wr)
1384 fput(ts->wr); 853 fput(ts->wr);
854
1385 kfree(ts); 855 kfree(ts);
1386} 856}
1387 857
@@ -1402,31 +872,23 @@ static inline int valid_ipaddr4(const char *buf)
1402 return 0; 872 return 0;
1403} 873}
1404 874
1405static struct p9_trans * 875static int
1406p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu) 876p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
1407{ 877{
1408 int err; 878 int err;
1409 struct p9_trans *trans;
1410 struct socket *csocket; 879 struct socket *csocket;
1411 struct sockaddr_in sin_server; 880 struct sockaddr_in sin_server;
1412 struct p9_fd_opts opts; 881 struct p9_fd_opts opts;
1413 struct p9_trans_fd *p; 882 struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
1414 883
1415 err = parse_opts(args, &opts); 884 err = parse_opts(args, &opts);
1416 if (err < 0) 885 if (err < 0)
1417 return ERR_PTR(err); 886 return err;
1418 887
1419 if (valid_ipaddr4(addr) < 0) 888 if (valid_ipaddr4(addr) < 0)
1420 return ERR_PTR(-EINVAL); 889 return -EINVAL;
1421 890
1422 csocket = NULL; 891 csocket = NULL;
1423 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
1424 if (!trans)
1425 return ERR_PTR(-ENOMEM);
1426 trans->msize = msize;
1427 trans->extended = dotu;
1428 trans->rpc = p9_fd_rpc;
1429 trans->close = p9_fd_close;
1430 892
1431 sin_server.sin_family = AF_INET; 893 sin_server.sin_family = AF_INET;
1432 sin_server.sin_addr.s_addr = in_aton(addr); 894 sin_server.sin_addr.s_addr = in_aton(addr);
@@ -1449,45 +911,38 @@ p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu)
1449 goto error; 911 goto error;
1450 } 912 }
1451 913
1452 err = p9_socket_open(trans, csocket); 914 err = p9_socket_open(client, csocket);
1453 if (err < 0) 915 if (err < 0)
1454 goto error; 916 goto error;
1455 917
1456 p = (struct p9_trans_fd *) trans->priv; 918 p = (struct p9_trans_fd *) client->trans;
1457 p->conn = p9_conn_create(trans); 919 p->conn = p9_conn_create(client);
1458 if (IS_ERR(p->conn)) { 920 if (IS_ERR(p->conn)) {
1459 err = PTR_ERR(p->conn); 921 err = PTR_ERR(p->conn);
1460 p->conn = NULL; 922 p->conn = NULL;
1461 goto error; 923 goto error;
1462 } 924 }
1463 925
1464 return trans; 926 return 0;
1465 927
1466error: 928error:
1467 if (csocket) 929 if (csocket)
1468 sock_release(csocket); 930 sock_release(csocket);
1469 931
1470 kfree(trans); 932 kfree(p);
1471 return ERR_PTR(err); 933
934 return err;
1472} 935}
1473 936
1474static struct p9_trans * 937static int
1475p9_trans_create_unix(const char *addr, char *args, int msize, 938p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
1476 unsigned char dotu)
1477{ 939{
1478 int err; 940 int err;
1479 struct socket *csocket; 941 struct socket *csocket;
1480 struct sockaddr_un sun_server; 942 struct sockaddr_un sun_server;
1481 struct p9_trans *trans; 943 struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
1482 struct p9_trans_fd *p;
1483 944
1484 csocket = NULL; 945 csocket = NULL;
1485 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
1486 if (!trans)
1487 return ERR_PTR(-ENOMEM);
1488
1489 trans->rpc = p9_fd_rpc;
1490 trans->close = p9_fd_close;
1491 946
1492 if (strlen(addr) > UNIX_PATH_MAX) { 947 if (strlen(addr) > UNIX_PATH_MAX) {
1493 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", 948 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
@@ -1508,79 +963,69 @@ p9_trans_create_unix(const char *addr, char *args, int msize,
1508 goto error; 963 goto error;
1509 } 964 }
1510 965
1511 err = p9_socket_open(trans, csocket); 966 err = p9_socket_open(client, csocket);
1512 if (err < 0) 967 if (err < 0)
1513 goto error; 968 goto error;
1514 969
1515 trans->msize = msize; 970 p = (struct p9_trans_fd *) client->trans;
1516 trans->extended = dotu; 971 p->conn = p9_conn_create(client);
1517 p = (struct p9_trans_fd *) trans->priv;
1518 p->conn = p9_conn_create(trans);
1519 if (IS_ERR(p->conn)) { 972 if (IS_ERR(p->conn)) {
1520 err = PTR_ERR(p->conn); 973 err = PTR_ERR(p->conn);
1521 p->conn = NULL; 974 p->conn = NULL;
1522 goto error; 975 goto error;
1523 } 976 }
1524 977
1525 return trans; 978 return 0;
1526 979
1527error: 980error:
1528 if (csocket) 981 if (csocket)
1529 sock_release(csocket); 982 sock_release(csocket);
1530 983
1531 kfree(trans); 984 kfree(p);
1532 return ERR_PTR(err); 985 return err;
1533} 986}
1534 987
1535static struct p9_trans * 988static int
1536p9_trans_create_fd(const char *name, char *args, int msize, 989p9_fd_create(struct p9_client *client, const char *addr, char *args)
1537 unsigned char extended)
1538{ 990{
1539 int err; 991 int err;
1540 struct p9_trans *trans;
1541 struct p9_fd_opts opts; 992 struct p9_fd_opts opts;
1542 struct p9_trans_fd *p; 993 struct p9_trans_fd *p = NULL; /* this get allocated in p9_fd_open */
1543 994
1544 parse_opts(args, &opts); 995 parse_opts(args, &opts);
1545 996
1546 if (opts.rfd == ~0 || opts.wfd == ~0) { 997 if (opts.rfd == ~0 || opts.wfd == ~0) {
1547 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); 998 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
1548 return ERR_PTR(-ENOPROTOOPT); 999 return -ENOPROTOOPT;
1549 } 1000 }
1550 1001
1551 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); 1002 err = p9_fd_open(client, opts.rfd, opts.wfd);
1552 if (!trans)
1553 return ERR_PTR(-ENOMEM);
1554
1555 trans->rpc = p9_fd_rpc;
1556 trans->close = p9_fd_close;
1557
1558 err = p9_fd_open(trans, opts.rfd, opts.wfd);
1559 if (err < 0) 1003 if (err < 0)
1560 goto error; 1004 goto error;
1561 1005
1562 trans->msize = msize; 1006 p = (struct p9_trans_fd *) client->trans;
1563 trans->extended = extended; 1007 p->conn = p9_conn_create(client);
1564 p = (struct p9_trans_fd *) trans->priv;
1565 p->conn = p9_conn_create(trans);
1566 if (IS_ERR(p->conn)) { 1008 if (IS_ERR(p->conn)) {
1567 err = PTR_ERR(p->conn); 1009 err = PTR_ERR(p->conn);
1568 p->conn = NULL; 1010 p->conn = NULL;
1569 goto error; 1011 goto error;
1570 } 1012 }
1571 1013
1572 return trans; 1014 return 0;
1573 1015
1574error: 1016error:
1575 kfree(trans); 1017 kfree(p);
1576 return ERR_PTR(err); 1018 return err;
1577} 1019}
1578 1020
1579static struct p9_trans_module p9_tcp_trans = { 1021static struct p9_trans_module p9_tcp_trans = {
1580 .name = "tcp", 1022 .name = "tcp",
1581 .maxsize = MAX_SOCK_BUF, 1023 .maxsize = MAX_SOCK_BUF,
1582 .def = 1, 1024 .def = 1,
1583 .create = p9_trans_create_tcp, 1025 .create = p9_fd_create_tcp,
1026 .close = p9_fd_close,
1027 .request = p9_fd_request,
1028 .cancel = p9_fd_cancel,
1584 .owner = THIS_MODULE, 1029 .owner = THIS_MODULE,
1585}; 1030};
1586 1031
@@ -1588,7 +1033,10 @@ static struct p9_trans_module p9_unix_trans = {
1588 .name = "unix", 1033 .name = "unix",
1589 .maxsize = MAX_SOCK_BUF, 1034 .maxsize = MAX_SOCK_BUF,
1590 .def = 0, 1035 .def = 0,
1591 .create = p9_trans_create_unix, 1036 .create = p9_fd_create_unix,
1037 .close = p9_fd_close,
1038 .request = p9_fd_request,
1039 .cancel = p9_fd_cancel,
1592 .owner = THIS_MODULE, 1040 .owner = THIS_MODULE,
1593}; 1041};
1594 1042
@@ -1596,23 +1044,71 @@ static struct p9_trans_module p9_fd_trans = {
1596 .name = "fd", 1044 .name = "fd",
1597 .maxsize = MAX_SOCK_BUF, 1045 .maxsize = MAX_SOCK_BUF,
1598 .def = 0, 1046 .def = 0,
1599 .create = p9_trans_create_fd, 1047 .create = p9_fd_create,
1048 .close = p9_fd_close,
1049 .request = p9_fd_request,
1050 .cancel = p9_fd_cancel,
1600 .owner = THIS_MODULE, 1051 .owner = THIS_MODULE,
1601}; 1052};
1602 1053
1603int p9_trans_fd_init(void) 1054/**
1055 * p9_poll_proc - poll worker thread
1056 * @a: thread state and arguments
1057 *
1058 * polls all v9fs transports for new events and queues the appropriate
1059 * work to the work queue
1060 *
1061 */
1062
1063static int p9_poll_proc(void *a)
1604{ 1064{
1605 int i; 1065 unsigned long flags;
1066
1067 P9_DPRINTK(P9_DEBUG_TRANS, "start %p\n", current);
1068 repeat:
1069 spin_lock_irqsave(&p9_poll_lock, flags);
1070 while (!list_empty(&p9_poll_pending_list)) {
1071 struct p9_conn *conn = list_first_entry(&p9_poll_pending_list,
1072 struct p9_conn,
1073 poll_pending_link);
1074 list_del_init(&conn->poll_pending_link);
1075 spin_unlock_irqrestore(&p9_poll_lock, flags);
1076
1077 p9_poll_mux(conn);
1078
1079 spin_lock_irqsave(&p9_poll_lock, flags);
1080 }
1081 spin_unlock_irqrestore(&p9_poll_lock, flags);
1082
1083 set_current_state(TASK_INTERRUPTIBLE);
1084 if (list_empty(&p9_poll_pending_list)) {
1085 P9_DPRINTK(P9_DEBUG_TRANS, "sleeping...\n");
1086 schedule();
1087 }
1088 __set_current_state(TASK_RUNNING);
1089
1090 if (!kthread_should_stop())
1091 goto repeat;
1606 1092
1607 for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) 1093 P9_DPRINTK(P9_DEBUG_TRANS, "finish\n");
1608 p9_mux_poll_tasks[i].task = NULL; 1094 return 0;
1095}
1609 1096
1097int p9_trans_fd_init(void)
1098{
1610 p9_mux_wq = create_workqueue("v9fs"); 1099 p9_mux_wq = create_workqueue("v9fs");
1611 if (!p9_mux_wq) { 1100 if (!p9_mux_wq) {
1612 printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n"); 1101 printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
1613 return -ENOMEM; 1102 return -ENOMEM;
1614 } 1103 }
1615 1104
1105 p9_poll_task = kthread_run(p9_poll_proc, NULL, "v9fs-poll");
1106 if (IS_ERR(p9_poll_task)) {
1107 destroy_workqueue(p9_mux_wq);
1108 printk(KERN_WARNING "v9fs: mux: creating poll task failed\n");
1109 return PTR_ERR(p9_poll_task);
1110 }
1111
1616 v9fs_register_trans(&p9_tcp_trans); 1112 v9fs_register_trans(&p9_tcp_trans);
1617 v9fs_register_trans(&p9_unix_trans); 1113 v9fs_register_trans(&p9_unix_trans);
1618 v9fs_register_trans(&p9_fd_trans); 1114 v9fs_register_trans(&p9_fd_trans);
@@ -1622,6 +1118,7 @@ int p9_trans_fd_init(void)
1622 1118
1623void p9_trans_fd_exit(void) 1119void p9_trans_fd_exit(void)
1624{ 1120{
1121 kthread_stop(p9_poll_task);
1625 v9fs_unregister_trans(&p9_tcp_trans); 1122 v9fs_unregister_trans(&p9_tcp_trans);
1626 v9fs_unregister_trans(&p9_unix_trans); 1123 v9fs_unregister_trans(&p9_unix_trans);
1627 v9fs_unregister_trans(&p9_fd_trans); 1124 v9fs_unregister_trans(&p9_fd_trans);
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 94912e077a55..2d7781ec663b 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -1,12 +1,10 @@
1/* 1/*
2 * The Guest 9p transport driver 2 * The Virtio 9p transport driver
3 * 3 *
4 * This is a block based transport driver based on the lguest block driver 4 * This is a block based transport driver based on the lguest block driver
5 * code. 5 * code.
6 * 6 *
7 */ 7 * Copyright (C) 2007, 2008 Eric Van Hensbergen, IBM Corporation
8/*
9 * Copyright (C) 2007 Eric Van Hensbergen, IBM Corporation
10 * 8 *
11 * Based on virtio console driver 9 * Based on virtio console driver
12 * Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation 10 * Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
@@ -41,6 +39,7 @@
41#include <linux/file.h> 39#include <linux/file.h>
42#include <net/9p/9p.h> 40#include <net/9p/9p.h>
43#include <linux/parser.h> 41#include <linux/parser.h>
42#include <net/9p/client.h>
44#include <net/9p/transport.h> 43#include <net/9p/transport.h>
45#include <linux/scatterlist.h> 44#include <linux/scatterlist.h>
46#include <linux/virtio.h> 45#include <linux/virtio.h>
@@ -53,50 +52,6 @@ static DEFINE_MUTEX(virtio_9p_lock);
53/* global which tracks highest initialized channel */ 52/* global which tracks highest initialized channel */
54static int chan_index; 53static int chan_index;
55 54
56#define P9_INIT_MAXTAG 16
57
58
59/**
60 * enum p9_req_status_t - virtio request status
61 * @REQ_STATUS_IDLE: request slot unused
62 * @REQ_STATUS_SENT: request sent to server
63 * @REQ_STATUS_RCVD: response received from server
64 * @REQ_STATUS_FLSH: request has been flushed
65 *
66 * The @REQ_STATUS_IDLE state is used to mark a request slot as unused
67 * but use is actually tracked by the idpool structure which handles tag
68 * id allocation.
69 *
70 */
71
72enum p9_req_status_t {
73 REQ_STATUS_IDLE,
74 REQ_STATUS_SENT,
75 REQ_STATUS_RCVD,
76 REQ_STATUS_FLSH,
77};
78
79/**
80 * struct p9_req_t - virtio request slots
81 * @status: status of this request slot
82 * @wq: wait_queue for the client to block on for this request
83 *
84 * The virtio transport uses an array to track outstanding requests
85 * instead of a list. While this may incurr overhead during initial
86 * allocation or expansion, it makes request lookup much easier as the
87 * tag id is a index into an array. (We use tag+1 so that we can accomodate
88 * the -1 tag for the T_VERSION request).
89 * This also has the nice effect of only having to allocate wait_queues
90 * once, instead of constantly allocating and freeing them. Its possible
91 * other resources could benefit from this scheme as well.
92 *
93 */
94
95struct p9_req_t {
96 int status;
97 wait_queue_head_t *wq;
98};
99
100/** 55/**
101 * struct virtio_chan - per-instance transport information 56 * struct virtio_chan - per-instance transport information
102 * @initialized: whether the channel is initialized 57 * @initialized: whether the channel is initialized
@@ -121,67 +76,14 @@ static struct virtio_chan {
121 76
122 spinlock_t lock; 77 spinlock_t lock;
123 78
79 struct p9_client *client;
124 struct virtio_device *vdev; 80 struct virtio_device *vdev;
125 struct virtqueue *vq; 81 struct virtqueue *vq;
126 82
127 struct p9_idpool *tagpool;
128 struct p9_req_t *reqs;
129 int max_tag;
130
131 /* Scatterlist: can be too big for stack. */ 83 /* Scatterlist: can be too big for stack. */
132 struct scatterlist sg[VIRTQUEUE_NUM]; 84 struct scatterlist sg[VIRTQUEUE_NUM];
133} channels[MAX_9P_CHAN]; 85} channels[MAX_9P_CHAN];
134 86
135/**
136 * p9_lookup_tag - Lookup requests by tag
137 * @c: virtio channel to lookup tag within
138 * @tag: numeric id for transaction
139 *
140 * this is a simple array lookup, but will grow the
141 * request_slots as necessary to accomodate transaction
142 * ids which did not previously have a slot.
143 *
144 * Bugs: there is currently no upper limit on request slots set
145 * here, but that should be constrained by the id accounting.
146 */
147
148static struct p9_req_t *p9_lookup_tag(struct virtio_chan *c, u16 tag)
149{
150 /* This looks up the original request by tag so we know which
151 * buffer to read the data into */
152 tag++;
153
154 while (tag >= c->max_tag) {
155 int old_max = c->max_tag;
156 int count;
157
158 if (c->max_tag)
159 c->max_tag *= 2;
160 else
161 c->max_tag = P9_INIT_MAXTAG;
162
163 c->reqs = krealloc(c->reqs, sizeof(struct p9_req_t)*c->max_tag,
164 GFP_ATOMIC);
165 if (!c->reqs) {
166 printk(KERN_ERR "Couldn't grow tag array\n");
167 BUG();
168 }
169 for (count = old_max; count < c->max_tag; count++) {
170 c->reqs[count].status = REQ_STATUS_IDLE;
171 c->reqs[count].wq = kmalloc(sizeof(wait_queue_head_t),
172 GFP_ATOMIC);
173 if (!c->reqs[count].wq) {
174 printk(KERN_ERR "Couldn't grow tag array\n");
175 BUG();
176 }
177 init_waitqueue_head(c->reqs[count].wq);
178 }
179 }
180
181 return &c->reqs[tag];
182}
183
184
185/* How many bytes left in this page. */ 87/* How many bytes left in this page. */
186static unsigned int rest_of_page(void *data) 88static unsigned int rest_of_page(void *data)
187{ 89{
@@ -197,25 +99,13 @@ static unsigned int rest_of_page(void *data)
197 * 99 *
198 */ 100 */
199 101
200static void p9_virtio_close(struct p9_trans *trans) 102static void p9_virtio_close(struct p9_client *client)
201{ 103{
202 struct virtio_chan *chan = trans->priv; 104 struct virtio_chan *chan = client->trans;
203 int count;
204 unsigned long flags;
205
206 spin_lock_irqsave(&chan->lock, flags);
207 p9_idpool_destroy(chan->tagpool);
208 for (count = 0; count < chan->max_tag; count++)
209 kfree(chan->reqs[count].wq);
210 kfree(chan->reqs);
211 chan->max_tag = 0;
212 spin_unlock_irqrestore(&chan->lock, flags);
213 105
214 mutex_lock(&virtio_9p_lock); 106 mutex_lock(&virtio_9p_lock);
215 chan->inuse = false; 107 chan->inuse = false;
216 mutex_unlock(&virtio_9p_lock); 108 mutex_unlock(&virtio_9p_lock);
217
218 kfree(trans);
219} 109}
220 110
221/** 111/**
@@ -236,17 +126,16 @@ static void req_done(struct virtqueue *vq)
236 struct virtio_chan *chan = vq->vdev->priv; 126 struct virtio_chan *chan = vq->vdev->priv;
237 struct p9_fcall *rc; 127 struct p9_fcall *rc;
238 unsigned int len; 128 unsigned int len;
239 unsigned long flags;
240 struct p9_req_t *req; 129 struct p9_req_t *req;
241 130
242 spin_lock_irqsave(&chan->lock, flags); 131 P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
132
243 while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) { 133 while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) {
244 req = p9_lookup_tag(chan, rc->tag); 134 P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
245 req->status = REQ_STATUS_RCVD; 135 P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
246 wake_up(req->wq); 136 req = p9_tag_lookup(chan->client, rc->tag);
137 p9_client_cb(chan->client, req);
247 } 138 }
248 /* In case queue is stopped waiting for more buffers. */
249 spin_unlock_irqrestore(&chan->lock, flags);
250} 139}
251 140
252/** 141/**
@@ -283,8 +172,14 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data,
283 return index-start; 172 return index-start;
284} 173}
285 174
175/* We don't currently allow canceling of virtio requests */
176static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
177{
178 return 1;
179}
180
286/** 181/**
287 * p9_virtio_rpc - issue a request and wait for a response 182 * p9_virtio_request - issue a request
288 * @t: transport state 183 * @t: transport state
289 * @tc: &p9_fcall request to transmit 184 * @tc: &p9_fcall request to transmit
290 * @rc: &p9_fcall to put reponse into 185 * @rc: &p9_fcall to put reponse into
@@ -292,44 +187,22 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data,
292 */ 187 */
293 188
294static int 189static int
295p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) 190p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
296{ 191{
297 int in, out; 192 int in, out;
298 int n, err, size; 193 struct virtio_chan *chan = client->trans;
299 struct virtio_chan *chan = t->priv; 194 char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
300 char *rdata;
301 struct p9_req_t *req;
302 unsigned long flags;
303
304 if (*rc == NULL) {
305 *rc = kmalloc(sizeof(struct p9_fcall) + t->msize, GFP_KERNEL);
306 if (!*rc)
307 return -ENOMEM;
308 }
309
310 rdata = (char *)*rc+sizeof(struct p9_fcall);
311
312 n = P9_NOTAG;
313 if (tc->id != P9_TVERSION) {
314 n = p9_idpool_get(chan->tagpool);
315 if (n < 0)
316 return -ENOMEM;
317 }
318
319 spin_lock_irqsave(&chan->lock, flags);
320 req = p9_lookup_tag(chan, n);
321 spin_unlock_irqrestore(&chan->lock, flags);
322 195
323 p9_set_tag(tc, n); 196 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
324 197
325 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc tag %d\n", n); 198 out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata,
326 199 req->tc->size);
327 out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, tc->sdata, tc->size); 200 in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata,
328 in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, t->msize); 201 client->msize);
329 202
330 req->status = REQ_STATUS_SENT; 203 req->status = REQ_STATUS_SENT;
331 204
332 if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, tc)) { 205 if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, req->tc)) {
333 P9_DPRINTK(P9_DEBUG_TRANS, 206 P9_DPRINTK(P9_DEBUG_TRANS,
334 "9p debug: virtio rpc add_buf returned failure"); 207 "9p debug: virtio rpc add_buf returned failure");
335 return -EIO; 208 return -EIO;
@@ -337,31 +210,7 @@ p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc)
337 210
338 chan->vq->vq_ops->kick(chan->vq); 211 chan->vq->vq_ops->kick(chan->vq);
339 212
340 wait_event(*req->wq, req->status == REQ_STATUS_RCVD); 213 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
341
342 size = le32_to_cpu(*(__le32 *) rdata);
343
344 err = p9_deserialize_fcall(rdata, size, *rc, t->extended);
345 if (err < 0) {
346 P9_DPRINTK(P9_DEBUG_TRANS,
347 "9p debug: virtio rpc deserialize returned %d\n", err);
348 return err;
349 }
350
351#ifdef CONFIG_NET_9P_DEBUG
352 if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
353 char buf[150];
354
355 p9_printfcall(buf, sizeof(buf), *rc, t->extended);
356 printk(KERN_NOTICE ">>> %p %s\n", t, buf);
357 }
358#endif
359
360 if (n != P9_NOTAG && p9_idpool_check(n, chan->tagpool))
361 p9_idpool_put(n, chan->tagpool);
362
363 req->status = REQ_STATUS_IDLE;
364
365 return 0; 214 return 0;
366} 215}
367 216
@@ -422,10 +271,9 @@ fail:
422 271
423/** 272/**
424 * p9_virtio_create - allocate a new virtio channel 273 * p9_virtio_create - allocate a new virtio channel
274 * @client: client instance invoking this transport
425 * @devname: string identifying the channel to connect to (unused) 275 * @devname: string identifying the channel to connect to (unused)
426 * @args: args passed from sys_mount() for per-transport options (unused) 276 * @args: args passed from sys_mount() for per-transport options (unused)
427 * @msize: requested maximum packet size
428 * @extended: 9p2000.u enabled flag
429 * 277 *
430 * This sets up a transport channel for 9p communication. Right now 278 * This sets up a transport channel for 9p communication. Right now
431 * we only match the first available channel, but eventually we couldlook up 279 * we only match the first available channel, but eventually we couldlook up
@@ -441,11 +289,9 @@ fail:
441 * 289 *
442 */ 290 */
443 291
444static struct p9_trans * 292static int
445p9_virtio_create(const char *devname, char *args, int msize, 293p9_virtio_create(struct p9_client *client, const char *devname, char *args)
446 unsigned char extended)
447{ 294{
448 struct p9_trans *trans;
449 struct virtio_chan *chan = channels; 295 struct virtio_chan *chan = channels;
450 int index = 0; 296 int index = 0;
451 297
@@ -463,30 +309,13 @@ p9_virtio_create(const char *devname, char *args, int msize,
463 309
464 if (index >= MAX_9P_CHAN) { 310 if (index >= MAX_9P_CHAN) {
465 printk(KERN_ERR "9p: no channels available\n"); 311 printk(KERN_ERR "9p: no channels available\n");
466 return ERR_PTR(-ENODEV); 312 return -ENODEV;
467 } 313 }
468 314
469 chan->tagpool = p9_idpool_create(); 315 client->trans = (void *)chan;
470 if (IS_ERR(chan->tagpool)) { 316 chan->client = client;
471 printk(KERN_ERR "9p: couldn't allocate tagpool\n");
472 return ERR_PTR(-ENOMEM);
473 }
474 p9_idpool_get(chan->tagpool); /* reserve tag 0 */
475 chan->max_tag = 0;
476 chan->reqs = NULL;
477
478 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
479 if (!trans) {
480 printk(KERN_ERR "9p: couldn't allocate transport\n");
481 return ERR_PTR(-ENOMEM);
482 }
483 trans->extended = extended;
484 trans->msize = msize;
485 trans->close = p9_virtio_close;
486 trans->rpc = p9_virtio_rpc;
487 trans->priv = chan;
488 317
489 return trans; 318 return 0;
490} 319}
491 320
492/** 321/**
@@ -526,6 +355,9 @@ static struct virtio_driver p9_virtio_drv = {
526static struct p9_trans_module p9_virtio_trans = { 355static struct p9_trans_module p9_virtio_trans = {
527 .name = "virtio", 356 .name = "virtio",
528 .create = p9_virtio_create, 357 .create = p9_virtio_create,
358 .close = p9_virtio_close,
359 .request = p9_virtio_request,
360 .cancel = p9_virtio_cancel,
529 .maxsize = PAGE_SIZE*16, 361 .maxsize = PAGE_SIZE*16,
530 .def = 0, 362 .def = 0,
531 .owner = THIS_MODULE, 363 .owner = THIS_MODULE,
diff --git a/net/9p/util.c b/net/9p/util.c
index 958fc58cd1ff..dc4ec05ad93d 100644
--- a/net/9p/util.c
+++ b/net/9p/util.c
@@ -105,6 +105,7 @@ retry:
105 else if (error) 105 else if (error)
106 return -1; 106 return -1;
107 107
108 P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", i, p);
108 return i; 109 return i;
109} 110}
110EXPORT_SYMBOL(p9_idpool_get); 111EXPORT_SYMBOL(p9_idpool_get);
@@ -121,6 +122,9 @@ EXPORT_SYMBOL(p9_idpool_get);
121void p9_idpool_put(int id, struct p9_idpool *p) 122void p9_idpool_put(int id, struct p9_idpool *p)
122{ 123{
123 unsigned long flags; 124 unsigned long flags;
125
126 P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", id, p);
127
124 spin_lock_irqsave(&p->lock, flags); 128 spin_lock_irqsave(&p->lock, flags);
125 idr_remove(&p->pool, id); 129 idr_remove(&p->pool, id);
126 spin_unlock_irqrestore(&p->lock, flags); 130 spin_unlock_irqrestore(&p->lock, flags);