aboutsummaryrefslogtreecommitdiffstats
path: root/fs/9p
diff options
context:
space:
mode:
authorLatchesar Ionkov <lucho@ionkov.net>2006-01-08 04:05:00 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 23:14:06 -0500
commit531b1094b74365dcc55fa464d28a9a2497ae825d (patch)
treea0384dabe3be1c844166d028b3ef7c21c3dfe5fc /fs/9p
parentd8da097afb765654c866062148fd98b11db9003e (diff)
[PATCH] v9fs: zero copy implementation
Performance enhancement reducing the number of copies in the data and stat paths. Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> Cc: Eric Van Hensbergen <ericvh@ericvh.myip.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/9p')
-rw-r--r--fs/9p/9p.c302
-rw-r--r--fs/9p/9p.h75
-rw-r--r--fs/9p/Makefile10
-rw-r--r--fs/9p/conv.c895
-rw-r--r--fs/9p/conv.h28
-rw-r--r--fs/9p/debug.h23
-rw-r--r--fs/9p/error.c10
-rw-r--r--fs/9p/error.h3
-rw-r--r--fs/9p/fid.c3
-rw-r--r--fs/9p/mux.c157
-rw-r--r--fs/9p/trans_sock.c1
-rw-r--r--fs/9p/v9fs.c3
-rw-r--r--fs/9p/v9fs_vfs.h5
-rw-r--r--fs/9p/vfs_dentry.c4
-rw-r--r--fs/9p/vfs_dir.c31
-rw-r--r--fs/9p/vfs_file.c25
-rw-r--r--fs/9p/vfs_inode.c545
-rw-r--r--fs/9p/vfs_super.c10
18 files changed, 1083 insertions, 1047 deletions
diff --git a/fs/9p/9p.c b/fs/9p/9p.c
index a3a1ac610723..dc3ce44ec836 100644
--- a/fs/9p/9p.c
+++ b/fs/9p/9p.c
@@ -1,8 +1,9 @@
1/* 1/*
2 * linux/fs/9p/9p.c 2 * linux/fs/9p/9p.c
3 * 3 *
4 * This file contains functions 9P2000 functions 4 * This file contains functions to perform synchronous 9P calls
5 * 5 *
6 * Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 * 9 *
@@ -33,6 +34,7 @@
33#include "debug.h" 34#include "debug.h"
34#include "v9fs.h" 35#include "v9fs.h"
35#include "9p.h" 36#include "9p.h"
37#include "conv.h"
36#include "mux.h" 38#include "mux.h"
37 39
38/** 40/**
@@ -46,17 +48,21 @@
46 48
47int 49int
48v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, 50v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
49 char *version, struct v9fs_fcall **fcall) 51 char *version, struct v9fs_fcall **rcp)
50{ 52{
51 struct v9fs_fcall msg; 53 int ret;
54 struct v9fs_fcall *tc;
52 55
53 dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version); 56 dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
54 msg.id = TVERSION; 57 tc = v9fs_create_tversion(msize, version);
55 msg.tag = ~0;
56 msg.params.tversion.msize = msize;
57 msg.params.tversion.version = version;
58 58
59 return v9fs_mux_rpc(v9ses->mux, &msg, fcall); 59 if (!IS_ERR(tc)) {
60 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
61 kfree(tc);
62 } else
63 ret = PTR_ERR(tc);
64
65 return ret;
60} 66}
61 67
62/** 68/**
@@ -72,19 +78,23 @@ v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
72 78
73int 79int
74v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, 80v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
75 u32 fid, u32 afid, struct v9fs_fcall **fcall) 81 u32 fid, u32 afid, struct v9fs_fcall **rcp)
76{ 82{
77 struct v9fs_fcall msg; 83 int ret;
84 struct v9fs_fcall* tc;
78 85
79 dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname, 86 dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
80 aname, fid, afid); 87 aname, fid, afid);
81 msg.id = TATTACH;
82 msg.params.tattach.fid = fid;
83 msg.params.tattach.afid = afid;
84 msg.params.tattach.uname = uname;
85 msg.params.tattach.aname = aname;
86 88
87 return v9fs_mux_rpc(v9ses->mux, &msg, fcall); 89 ret = -ENOMEM;
90 tc = v9fs_create_tattach(fid, afid, uname, aname);
91 if (!IS_ERR(tc)) {
92 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
93 kfree(tc);
94 } else
95 ret = PTR_ERR(tc);
96
97 return ret;
88} 98}
89 99
90static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc, 100static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
@@ -117,24 +127,28 @@ static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
117 * @fcall: pointer to response fcall pointer 127 * @fcall: pointer to response fcall pointer
118 * 128 *
119 */ 129 */
130
120int 131int
121v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid) 132v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
122{ 133{
123 int err; 134 int ret;
124 struct v9fs_fcall *tc, *rc; 135 struct v9fs_fcall *tc, *rc;
125 136
126 tc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL);
127
128 dprintk(DEBUG_9P, "fid %d\n", fid); 137 dprintk(DEBUG_9P, "fid %d\n", fid);
129 tc->id = TCLUNK;
130 tc->params.tclunk.fid = fid;
131 138
132 err = v9fs_mux_rpc(v9ses->mux, tc, &rc); 139 ret = -ENOMEM;
133 if (err >= 0) { 140 rc = NULL;
134 v9fs_t_clunk_cb(v9ses, tc, rc, 0); 141 tc = v9fs_create_tclunk(fid);
135 } 142 if (!IS_ERR(tc))
143 ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
144 else
145 ret = PTR_ERR(tc);
146
147 if (ret)
148 dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret);
136 149
137 return err; 150 v9fs_t_clunk_cb(v9ses, tc, rc, ret);
151 return ret;
138} 152}
139 153
140/** 154/**
@@ -144,14 +158,22 @@ v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
144 * 158 *
145 */ 159 */
146 160
147int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag) 161int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag)
148{ 162{
149 struct v9fs_fcall msg; 163 int ret;
164 struct v9fs_fcall *tc;
150 165
151 dprintk(DEBUG_9P, "oldtag %d\n", tag); 166 dprintk(DEBUG_9P, "oldtag %d\n", oldtag);
152 msg.id = TFLUSH; 167
153 msg.params.tflush.oldtag = tag; 168 ret = -ENOMEM;
154 return v9fs_mux_rpc(v9ses->mux, &msg, NULL); 169 tc = v9fs_create_tflush(oldtag);
170 if (!IS_ERR(tc)) {
171 ret = v9fs_mux_rpc(v9ses->mux, tc, NULL);
172 kfree(tc);
173 } else
174 ret = PTR_ERR(tc);
175
176 return ret;
155} 177}
156 178
157/** 179/**
@@ -163,17 +185,22 @@ int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag)
163 */ 185 */
164 186
165int 187int
166v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall) 188v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp)
167{ 189{
168 struct v9fs_fcall msg; 190 int ret;
191 struct v9fs_fcall *tc;
169 192
170 dprintk(DEBUG_9P, "fid %d\n", fid); 193 dprintk(DEBUG_9P, "fid %d\n", fid);
171 if (fcall)
172 *fcall = NULL;
173 194
174 msg.id = TSTAT; 195 ret = -ENOMEM;
175 msg.params.tstat.fid = fid; 196 tc = v9fs_create_tstat(fid);
176 return v9fs_mux_rpc(v9ses->mux, &msg, fcall); 197 if (!IS_ERR(tc)) {
198 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
199 kfree(tc);
200 } else
201 ret = PTR_ERR(tc);
202
203 return ret;
177} 204}
178 205
179/** 206/**
@@ -187,16 +214,22 @@ v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall)
187 214
188int 215int
189v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, 216v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
190 struct v9fs_stat *stat, struct v9fs_fcall **fcall) 217 struct v9fs_wstat *wstat, struct v9fs_fcall **rcp)
191{ 218{
192 struct v9fs_fcall msg; 219 int ret;
220 struct v9fs_fcall *tc;
193 221
194 dprintk(DEBUG_9P, "fid %d length %d\n", fid, (int)stat->length); 222 dprintk(DEBUG_9P, "fid %d\n", fid);
195 msg.id = TWSTAT; 223
196 msg.params.twstat.fid = fid; 224 ret = -ENOMEM;
197 msg.params.twstat.stat = stat; 225 tc = v9fs_create_twstat(fid, wstat, v9ses->extended);
226 if (!IS_ERR(tc)) {
227 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
228 kfree(tc);
229 } else
230 ret = PTR_ERR(tc);
198 231
199 return v9fs_mux_rpc(v9ses->mux, &msg, fcall); 232 return ret;
200} 233}
201 234
202/** 235/**
@@ -213,23 +246,28 @@ v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
213 246
214int 247int
215v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, 248v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
216 char *name, struct v9fs_fcall **fcall) 249 char *name, struct v9fs_fcall **rcp)
217{ 250{
218 struct v9fs_fcall msg; 251 int ret;
252 struct v9fs_fcall *tc;
253 int nwname;
219 254
220 dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name); 255 dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
221 msg.id = TWALK; 256
222 msg.params.twalk.fid = fid; 257 if (name)
223 msg.params.twalk.newfid = newfid; 258 nwname = 1;
224 259 else
225 if (name) { 260 nwname = 0;
226 msg.params.twalk.nwname = 1; 261
227 msg.params.twalk.wnames = &name; 262 ret = -ENOMEM;
228 } else { 263 tc = v9fs_create_twalk(fid, newfid, nwname, &name);
229 msg.params.twalk.nwname = 0; 264 if (!IS_ERR(tc)) {
230 } 265 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
231 266 kfree(tc);
232 return v9fs_mux_rpc(v9ses->mux, &msg, fcall); 267 } else
268 ret = PTR_ERR(tc);
269
270 return ret;
233} 271}
234 272
235/** 273/**
@@ -244,19 +282,22 @@ v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
244 282
245int 283int
246v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode, 284v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
247 struct v9fs_fcall **fcall) 285 struct v9fs_fcall **rcp)
248{ 286{
249 struct v9fs_fcall msg; 287 int ret;
250 int errorno = -1; 288 struct v9fs_fcall *tc;
251 289
252 dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode); 290 dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
253 msg.id = TOPEN;
254 msg.params.topen.fid = fid;
255 msg.params.topen.mode = mode;
256 291
257 errorno = v9fs_mux_rpc(v9ses->mux, &msg, fcall); 292 ret = -ENOMEM;
293 tc = v9fs_create_topen(fid, mode);
294 if (!IS_ERR(tc)) {
295 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
296 kfree(tc);
297 } else
298 ret = PTR_ERR(tc);
258 299
259 return errorno; 300 return ret;
260} 301}
261 302
262/** 303/**
@@ -269,14 +310,22 @@ v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
269 310
270int 311int
271v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid, 312v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
272 struct v9fs_fcall **fcall) 313 struct v9fs_fcall **rcp)
273{ 314{
274 struct v9fs_fcall msg; 315 int ret;
316 struct v9fs_fcall *tc;
275 317
276 dprintk(DEBUG_9P, "fid %d\n", fid); 318 dprintk(DEBUG_9P, "fid %d\n", fid);
277 msg.id = TREMOVE; 319
278 msg.params.tremove.fid = fid; 320 ret = -ENOMEM;
279 return v9fs_mux_rpc(v9ses->mux, &msg, fcall); 321 tc = v9fs_create_tremove(fid);
322 if (!IS_ERR(tc)) {
323 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
324 kfree(tc);
325 } else
326 ret = PTR_ERR(tc);
327
328 return ret;
280} 329}
281 330
282/** 331/**
@@ -292,20 +341,23 @@ v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
292 341
293int 342int
294v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, 343v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
295 u32 perm, u8 mode, struct v9fs_fcall **fcall) 344 u32 perm, u8 mode, struct v9fs_fcall **rcp)
296{ 345{
297 struct v9fs_fcall msg; 346 int ret;
347 struct v9fs_fcall *tc;
298 348
299 dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n", 349 dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
300 fid, name, perm, mode); 350 fid, name, perm, mode);
301 351
302 msg.id = TCREATE; 352 ret = -ENOMEM;
303 msg.params.tcreate.fid = fid; 353 tc = v9fs_create_tcreate(fid, name, perm, mode);
304 msg.params.tcreate.name = name; 354 if (!IS_ERR(tc)) {
305 msg.params.tcreate.perm = perm; 355 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
306 msg.params.tcreate.mode = mode; 356 kfree(tc);
357 } else
358 ret = PTR_ERR(tc);
307 359
308 return v9fs_mux_rpc(v9ses->mux, &msg, fcall); 360 return ret;
309} 361}
310 362
311/** 363/**
@@ -320,31 +372,30 @@ v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
320 372
321int 373int
322v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset, 374v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
323 u32 count, struct v9fs_fcall **fcall) 375 u32 count, struct v9fs_fcall **rcp)
324{ 376{
325 struct v9fs_fcall msg; 377 int ret;
326 struct v9fs_fcall *rc = NULL; 378 struct v9fs_fcall *tc, *rc;
327 long errorno = -1;
328
329 dprintk(DEBUG_9P, "fid %d offset 0x%lx count 0x%x\n", fid,
330 (long unsigned int)offset, count);
331 msg.id = TREAD;
332 msg.params.tread.fid = fid;
333 msg.params.tread.offset = offset;
334 msg.params.tread.count = count;
335 errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc);
336
337 if (!errorno) {
338 errorno = rc->params.rread.count;
339 dump_data(rc->params.rread.data, rc->params.rread.count);
340 }
341
342 if (fcall)
343 *fcall = rc;
344 else
345 kfree(rc);
346 379
347 return errorno; 380 dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
381 (long long unsigned) offset, count);
382
383 ret = -ENOMEM;
384 tc = v9fs_create_tread(fid, offset, count);
385 if (!IS_ERR(tc)) {
386 ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
387 if (!ret)
388 ret = rc->params.rread.count;
389 if (rcp)
390 *rcp = rc;
391 else
392 kfree(rc);
393
394 kfree(tc);
395 } else
396 ret = PTR_ERR(tc);
397
398 return ret;
348} 399}
349 400
350/** 401/**
@@ -358,32 +409,31 @@ v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
358 */ 409 */
359 410
360int 411int
361v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, 412v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count,
362 u64 offset, u32 count, void *data, struct v9fs_fcall **fcall) 413 const char __user *data, struct v9fs_fcall **rcp)
363{ 414{
364 struct v9fs_fcall msg; 415 int ret;
365 struct v9fs_fcall *rc = NULL; 416 struct v9fs_fcall *tc, *rc;
366 long errorno = -1;
367 417
368 dprintk(DEBUG_9P, "fid %d offset 0x%llx count 0x%x\n", fid, 418 dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
369 (unsigned long long)offset, count); 419 (long long unsigned) offset, count);
370 dump_data(data, count);
371 420
372 msg.id = TWRITE; 421 ret = -ENOMEM;
373 msg.params.twrite.fid = fid; 422 tc = v9fs_create_twrite(fid, offset, count, data);
374 msg.params.twrite.offset = offset; 423 if (!IS_ERR(tc)) {
375 msg.params.twrite.count = count; 424 ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
376 msg.params.twrite.data = data;
377 425
378 errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc); 426 if (!ret)
427 ret = rc->params.rwrite.count;
428 if (rcp)
429 *rcp = rc;
430 else
431 kfree(rc);
379 432
380 if (!errorno) 433 kfree(tc);
381 errorno = rc->params.rwrite.count; 434 } else
435 ret = PTR_ERR(tc);
382 436
383 if (fcall) 437 return ret;
384 *fcall = rc;
385 else
386 kfree(rc);
387
388 return errorno;
389} 438}
439
diff --git a/fs/9p/9p.h b/fs/9p/9p.h
index 6355392786e2..007ff639777d 100644
--- a/fs/9p/9p.h
+++ b/fs/9p/9p.h
@@ -3,6 +3,7 @@
3 * 3 *
4 * 9P protocol definitions. 4 * 9P protocol definitions.
5 * 5 *
6 * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 * 9 *
@@ -102,10 +103,16 @@ enum {
102 103
103#define V9FS_NOTAG (u16)(~0) 104#define V9FS_NOTAG (u16)(~0)
104#define V9FS_NOFID (u32)(~0) 105#define V9FS_NOFID (u32)(~0)
106#define V9FS_MAXWELEM 16
105 107
106/* ample room for Twrite/Rread header (iounit) */ 108/* ample room for Twrite/Rread header (iounit) */
107#define V9FS_IOHDRSZ 24 109#define V9FS_IOHDRSZ 24
108 110
111struct v9fs_str {
112 u16 len;
113 char *str;
114};
115
109/* qids are the unique ID for a file (like an inode */ 116/* qids are the unique ID for a file (like an inode */
110struct v9fs_qid { 117struct v9fs_qid {
111 u8 type; 118 u8 type;
@@ -123,6 +130,29 @@ struct v9fs_stat {
123 u32 atime; 130 u32 atime;
124 u32 mtime; 131 u32 mtime;
125 u64 length; 132 u64 length;
133 struct v9fs_str name;
134 struct v9fs_str uid;
135 struct v9fs_str gid;
136 struct v9fs_str muid;
137 struct v9fs_str extension; /* 9p2000.u extensions */
138 u32 n_uid; /* 9p2000.u extensions */
139 u32 n_gid; /* 9p2000.u extensions */
140 u32 n_muid; /* 9p2000.u extensions */
141};
142
143/* file metadata (stat) structure used to create Twstat message
144 The is similar to v9fs_stat, but the strings don't point to
145 the same memory block and should be freed separately
146*/
147struct v9fs_wstat {
148 u16 size;
149 u16 type;
150 u32 dev;
151 struct v9fs_qid qid;
152 u32 mode;
153 u32 atime;
154 u32 mtime;
155 u64 length;
126 char *name; 156 char *name;
127 char *uid; 157 char *uid;
128 char *gid; 158 char *gid;
@@ -131,25 +161,24 @@ struct v9fs_stat {
131 u32 n_uid; /* 9p2000.u extensions */ 161 u32 n_uid; /* 9p2000.u extensions */
132 u32 n_gid; /* 9p2000.u extensions */ 162 u32 n_gid; /* 9p2000.u extensions */
133 u32 n_muid; /* 9p2000.u extensions */ 163 u32 n_muid; /* 9p2000.u extensions */
134 char data[0];
135}; 164};
136 165
137/* Structures for Protocol Operations */ 166/* Structures for Protocol Operations */
138 167
139struct Tversion { 168struct Tversion {
140 u32 msize; 169 u32 msize;
141 char *version; 170 struct v9fs_str version;
142}; 171};
143 172
144struct Rversion { 173struct Rversion {
145 u32 msize; 174 u32 msize;
146 char *version; 175 struct v9fs_str version;
147}; 176};
148 177
149struct Tauth { 178struct Tauth {
150 u32 afid; 179 u32 afid;
151 char *uname; 180 struct v9fs_str uname;
152 char *aname; 181 struct v9fs_str aname;
153}; 182};
154 183
155struct Rauth { 184struct Rauth {
@@ -157,12 +186,12 @@ struct Rauth {
157}; 186};
158 187
159struct Rerror { 188struct Rerror {
160 char *error; 189 struct v9fs_str error;
161 u32 errno; /* 9p2000.u extension */ 190 u32 errno; /* 9p2000.u extension */
162}; 191};
163 192
164struct Tflush { 193struct Tflush {
165 u32 oldtag; 194 u16 oldtag;
166}; 195};
167 196
168struct Rflush { 197struct Rflush {
@@ -171,8 +200,8 @@ struct Rflush {
171struct Tattach { 200struct Tattach {
172 u32 fid; 201 u32 fid;
173 u32 afid; 202 u32 afid;
174 char *uname; 203 struct v9fs_str uname;
175 char *aname; 204 struct v9fs_str aname;
176}; 205};
177 206
178struct Rattach { 207struct Rattach {
@@ -182,13 +211,13 @@ struct Rattach {
182struct Twalk { 211struct Twalk {
183 u32 fid; 212 u32 fid;
184 u32 newfid; 213 u32 newfid;
185 u32 nwname; 214 u16 nwname;
186 char **wnames; 215 struct v9fs_str wnames[16];
187}; 216};
188 217
189struct Rwalk { 218struct Rwalk {
190 u32 nwqid; 219 u16 nwqid;
191 struct v9fs_qid *wqids; 220 struct v9fs_qid wqids[16];
192}; 221};
193 222
194struct Topen { 223struct Topen {
@@ -203,7 +232,7 @@ struct Ropen {
203 232
204struct Tcreate { 233struct Tcreate {
205 u32 fid; 234 u32 fid;
206 char *name; 235 struct v9fs_str name;
207 u32 perm; 236 u32 perm;
208 u8 mode; 237 u8 mode;
209}; 238};
@@ -254,12 +283,12 @@ struct Tstat {
254}; 283};
255 284
256struct Rstat { 285struct Rstat {
257 struct v9fs_stat *stat; 286 struct v9fs_stat stat;
258}; 287};
259 288
260struct Twstat { 289struct Twstat {
261 u32 fid; 290 u32 fid;
262 struct v9fs_stat *stat; 291 struct v9fs_stat stat;
263}; 292};
264 293
265struct Rwstat { 294struct Rwstat {
@@ -274,6 +303,7 @@ struct v9fs_fcall {
274 u32 size; 303 u32 size;
275 u8 id; 304 u8 id;
276 u16 tag; 305 u16 tag;
306 void *sdata;
277 307
278 union { 308 union {
279 struct Tversion tversion; 309 struct Tversion tversion;
@@ -306,10 +336,12 @@ struct v9fs_fcall {
306 } params; 336 } params;
307}; 337};
308 338
309#define V9FS_FCALLHDRSZ (sizeof(struct v9fs_fcall) + \ 339#define PRINT_FCALL_ERROR(s, fcall) dprintk(DEBUG_ERROR, "%s: %.*s\n", s, \
310 sizeof(struct v9fs_stat) + 16*sizeof(struct v9fs_qid) + 16) 340 fcall?fcall->params.rerror.error.len:0, \
341 fcall?fcall->params.rerror.error.str:"");
311 342
312#define FCALL_ERROR(fcall) (fcall ? fcall->params.rerror.error : "") 343char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str);
344int v9fs_str_compare(char *buf, struct v9fs_str *str);
313 345
314int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, 346int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
315 char *version, struct v9fs_fcall **rcall); 347 char *version, struct v9fs_fcall **rcall);
@@ -325,7 +357,7 @@ int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid,
325 struct v9fs_fcall **rcall); 357 struct v9fs_fcall **rcall);
326 358
327int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, 359int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
328 struct v9fs_stat *stat, struct v9fs_fcall **rcall); 360 struct v9fs_wstat *wstat, struct v9fs_fcall **rcall);
329 361
330int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, 362int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
331 char *name, struct v9fs_fcall **rcall); 363 char *name, struct v9fs_fcall **rcall);
@@ -343,4 +375,5 @@ int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid,
343 u64 offset, u32 count, struct v9fs_fcall **rcall); 375 u64 offset, u32 count, struct v9fs_fcall **rcall);
344 376
345int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, 377int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
346 u32 count, void *data, struct v9fs_fcall **rcall); 378 u32 count, const char __user * data,
379 struct v9fs_fcall **rcall);
diff --git a/fs/9p/Makefile b/fs/9p/Makefile
index e4e4ffe5a7dc..3d023089707e 100644
--- a/fs/9p/Makefile
+++ b/fs/9p/Makefile
@@ -1,17 +1,17 @@
1obj-$(CONFIG_9P_FS) := 9p2000.o 1obj-$(CONFIG_9P_FS) := 9p2000.o
2 2
39p2000-objs := \ 39p2000-objs := \
4 trans_fd.o \
5 trans_sock.o \
6 mux.o \
7 9p.o \
8 conv.o \
4 vfs_super.o \ 9 vfs_super.o \
5 vfs_inode.o \ 10 vfs_inode.o \
6 vfs_file.o \ 11 vfs_file.o \
7 vfs_dir.o \ 12 vfs_dir.o \
8 vfs_dentry.o \ 13 vfs_dentry.o \
9 error.o \ 14 error.o \
10 mux.o \
11 trans_fd.o \
12 trans_sock.o \
13 9p.o \
14 conv.o \
15 v9fs.o \ 15 v9fs.o \
16 fid.o 16 fid.o
17 17
diff --git a/fs/9p/conv.c b/fs/9p/conv.c
index 1b9b15dfeaf0..f62434d435b3 100644
--- a/fs/9p/conv.c
+++ b/fs/9p/conv.c
@@ -30,7 +30,7 @@
30#include <linux/errno.h> 30#include <linux/errno.h>
31#include <linux/fs.h> 31#include <linux/fs.h>
32#include <linux/idr.h> 32#include <linux/idr.h>
33 33#include <asm/uaccess.h>
34#include "debug.h" 34#include "debug.h"
35#include "v9fs.h" 35#include "v9fs.h"
36#include "9p.h" 36#include "9p.h"
@@ -45,6 +45,37 @@ struct cbuf {
45 unsigned char *ep; 45 unsigned char *ep;
46}; 46};
47 47
48char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str)
49{
50 int n;
51
52 if (buflen < str->len)
53 n = buflen;
54 else
55 n = str->len;
56
57 memmove(buf, str->str, n - 1);
58
59 return buf;
60}
61
62int v9fs_str_compare(char *buf, struct v9fs_str *str)
63{
64 int n, ret;
65
66 ret = strncmp(buf, str->str, str->len);
67
68 if (!ret) {
69 n = strlen(buf);
70 if (n < str->len)
71 ret = -1;
72 else if (n > str->len)
73 ret = 1;
74 }
75
76 return ret;
77}
78
48static inline void buf_init(struct cbuf *buf, void *data, int datalen) 79static inline void buf_init(struct cbuf *buf, void *data, int datalen)
49{ 80{
50 buf->sp = buf->p = data; 81 buf->sp = buf->p = data;
@@ -58,12 +89,12 @@ static inline int buf_check_overflow(struct cbuf *buf)
58 89
59static inline int buf_check_size(struct cbuf *buf, int len) 90static inline int buf_check_size(struct cbuf *buf, int len)
60{ 91{
61 if (buf->p+len > buf->ep) { 92 if (buf->p + len > buf->ep && buf->p < buf->ep) {
62 if (buf->p < buf->ep) { 93 eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
63 eprintk(KERN_ERR, "buffer overflow\n"); 94 len, (int)(buf->ep - buf->p));
64 buf->p = buf->ep + 1; 95 dump_stack();
65 return 0; 96 buf->p = buf->ep + 1;
66 } 97 return 0;
67 } 98 }
68 99
69 return 1; 100 return 1;
@@ -127,14 +158,6 @@ static inline void buf_put_string(struct cbuf *buf, const char *s)
127 buf_put_stringn(buf, s, strlen(s)); 158 buf_put_stringn(buf, s, strlen(s));
128} 159}
129 160
130static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen)
131{
132 if (buf_check_size(buf, datalen)) {
133 memcpy(buf->p, data, datalen);
134 buf->p += datalen;
135 }
136}
137
138static inline u8 buf_get_int8(struct cbuf *buf) 161static inline u8 buf_get_int8(struct cbuf *buf)
139{ 162{
140 u8 ret = 0; 163 u8 ret = 0;
@@ -183,85 +206,37 @@ static inline u64 buf_get_int64(struct cbuf *buf)
183 return ret; 206 return ret;
184} 207}
185 208
186static inline int 209static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
187buf_get_string(struct cbuf *buf, char *data, unsigned int datalen)
188{
189 u16 len = 0;
190
191 len = buf_get_int16(buf);
192 if (!buf_check_overflow(buf) && buf_check_size(buf, len) && len+1>datalen) {
193 memcpy(data, buf->p, len);
194 data[len] = 0;
195 buf->p += len;
196 len++;
197 }
198
199 return len;
200}
201
202static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf)
203{
204 char *ret;
205 u16 len;
206
207 ret = NULL;
208 len = buf_get_int16(buf);
209
210 if (!buf_check_overflow(buf) && buf_check_size(buf, len) &&
211 buf_check_size(sbuf, len + 1)) {
212
213 memcpy(sbuf->p, buf->p, len);
214 sbuf->p[len] = 0;
215 ret = sbuf->p;
216 buf->p += len;
217 sbuf->p += len + 1;
218 }
219
220 return ret;
221}
222
223static inline int buf_get_data(struct cbuf *buf, void *data, int datalen)
224{ 210{
225 int ret = 0; 211 vstr->len = buf_get_int16(buf);
226 212 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
227 if (buf_check_size(buf, datalen)) { 213 vstr->str = buf->p;
228 memcpy(data, buf->p, datalen); 214 buf->p += vstr->len;
229 buf->p += datalen; 215 } else {
230 ret = datalen; 216 vstr->len = 0;
217 vstr->str = NULL;
231 } 218 }
232
233 return ret;
234} 219}
235 220
236static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, 221static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
237 int datalen)
238{ 222{
239 char *ret = NULL; 223 qid->type = buf_get_int8(bufp);
240 int n = 0; 224 qid->version = buf_get_int32(bufp);
241 225 qid->path = buf_get_int64(bufp);
242 if (buf_check_size(dbuf, datalen)) {
243 n = buf_get_data(buf, dbuf->p, datalen);
244 if (n > 0) {
245 ret = dbuf->p;
246 dbuf->p += n;
247 }
248 }
249
250 return ret;
251} 226}
252 227
253/** 228/**
254 * v9fs_size_stat - calculate the size of a variable length stat struct 229 * v9fs_size_wstat - calculate the size of a variable length stat struct
255 * @stat: metadata (stat) structure 230 * @stat: metadata (stat) structure
256 * @extended: non-zero if 9P2000.u 231 * @extended: non-zero if 9P2000.u
257 * 232 *
258 */ 233 */
259 234
260static int v9fs_size_stat(struct v9fs_stat *stat, int extended) 235static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
261{ 236{
262 int size = 0; 237 int size = 0;
263 238
264 if (stat == NULL) { 239 if (wstat == NULL) {
265 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); 240 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
266 return 0; 241 return 0;
267 } 242 }
@@ -278,81 +253,38 @@ static int v9fs_size_stat(struct v9fs_stat *stat, int extended)
278 8 + /* length[8] */ 253 8 + /* length[8] */
279 8; /* minimum sum of string lengths */ 254 8; /* minimum sum of string lengths */
280 255
281 if (stat->name) 256 if (wstat->name)
282 size += strlen(stat->name); 257 size += strlen(wstat->name);
283 if (stat->uid) 258 if (wstat->uid)
284 size += strlen(stat->uid); 259 size += strlen(wstat->uid);
285 if (stat->gid) 260 if (wstat->gid)
286 size += strlen(stat->gid); 261 size += strlen(wstat->gid);
287 if (stat->muid) 262 if (wstat->muid)
288 size += strlen(stat->muid); 263 size += strlen(wstat->muid);
289 264
290 if (extended) { 265 if (extended) {
291 size += 4 + /* n_uid[4] */ 266 size += 4 + /* n_uid[4] */
292 4 + /* n_gid[4] */ 267 4 + /* n_gid[4] */
293 4 + /* n_muid[4] */ 268 4 + /* n_muid[4] */
294 2; /* string length of extension[4] */ 269 2; /* string length of extension[4] */
295 if (stat->extension) 270 if (wstat->extension)
296 size += strlen(stat->extension); 271 size += strlen(wstat->extension);
297 } 272 }
298 273
299 return size; 274 return size;
300} 275}
301 276
302/** 277/**
303 * serialize_stat - safely format a stat structure for transmission 278 * buf_get_stat - safely decode a recieved metadata (stat) structure
304 * @stat: metadata (stat) structure
305 * @bufp: buffer to serialize structure into
306 * @extended: non-zero if 9P2000.u
307 *
308 */
309
310static int
311serialize_stat(struct v9fs_stat *stat, struct cbuf *bufp, int extended)
312{
313 buf_put_int16(bufp, stat->size);
314 buf_put_int16(bufp, stat->type);
315 buf_put_int32(bufp, stat->dev);
316 buf_put_int8(bufp, stat->qid.type);
317 buf_put_int32(bufp, stat->qid.version);
318 buf_put_int64(bufp, stat->qid.path);
319 buf_put_int32(bufp, stat->mode);
320 buf_put_int32(bufp, stat->atime);
321 buf_put_int32(bufp, stat->mtime);
322 buf_put_int64(bufp, stat->length);
323
324 buf_put_string(bufp, stat->name);
325 buf_put_string(bufp, stat->uid);
326 buf_put_string(bufp, stat->gid);
327 buf_put_string(bufp, stat->muid);
328
329 if (extended) {
330 buf_put_string(bufp, stat->extension);
331 buf_put_int32(bufp, stat->n_uid);
332 buf_put_int32(bufp, stat->n_gid);
333 buf_put_int32(bufp, stat->n_muid);
334 }
335
336 if (buf_check_overflow(bufp))
337 return 0;
338
339 return stat->size;
340}
341
342/**
343 * deserialize_stat - safely decode a recieved metadata (stat) structure
344 * @bufp: buffer to deserialize 279 * @bufp: buffer to deserialize
345 * @stat: metadata (stat) structure 280 * @stat: metadata (stat) structure
346 * @dbufp: buffer to deserialize variable strings into
347 * @extended: non-zero if 9P2000.u 281 * @extended: non-zero if 9P2000.u
348 * 282 *
349 */ 283 */
350 284
351static inline int 285static inline void
352deserialize_stat(struct cbuf *bufp, struct v9fs_stat *stat, 286buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
353 struct cbuf *dbufp, int extended)
354{ 287{
355
356 stat->size = buf_get_int16(bufp); 288 stat->size = buf_get_int16(bufp);
357 stat->type = buf_get_int16(bufp); 289 stat->type = buf_get_int16(bufp);
358 stat->dev = buf_get_int32(bufp); 290 stat->dev = buf_get_int32(bufp);
@@ -363,45 +295,17 @@ deserialize_stat(struct cbuf *bufp, struct v9fs_stat *stat,
363 stat->atime = buf_get_int32(bufp); 295 stat->atime = buf_get_int32(bufp);
364 stat->mtime = buf_get_int32(bufp); 296 stat->mtime = buf_get_int32(bufp);
365 stat->length = buf_get_int64(bufp); 297 stat->length = buf_get_int64(bufp);
366 stat->name = buf_get_stringb(bufp, dbufp); 298 buf_get_str(bufp, &stat->name);
367 stat->uid = buf_get_stringb(bufp, dbufp); 299 buf_get_str(bufp, &stat->uid);
368 stat->gid = buf_get_stringb(bufp, dbufp); 300 buf_get_str(bufp, &stat->gid);
369 stat->muid = buf_get_stringb(bufp, dbufp); 301 buf_get_str(bufp, &stat->muid);
370 302
371 if (extended) { 303 if (extended) {
372 stat->extension = buf_get_stringb(bufp, dbufp); 304 buf_get_str(bufp, &stat->extension);
373 stat->n_uid = buf_get_int32(bufp); 305 stat->n_uid = buf_get_int32(bufp);
374 stat->n_gid = buf_get_int32(bufp); 306 stat->n_gid = buf_get_int32(bufp);
375 stat->n_muid = buf_get_int32(bufp); 307 stat->n_muid = buf_get_int32(bufp);
376 } 308 }
377
378 if (buf_check_overflow(bufp) || buf_check_overflow(dbufp))
379 return 0;
380
381 return stat->size + 2;
382}
383
384/**
385 * deserialize_statb - wrapper for decoding a received metadata structure
386 * @bufp: buffer to deserialize
387 * @dbufp: buffer to deserialize variable strings into
388 * @extended: non-zero if 9P2000.u
389 *
390 */
391
392static inline struct v9fs_stat *deserialize_statb(struct cbuf *bufp,
393 struct cbuf *dbufp,
394 int extended)
395{
396 struct v9fs_stat *ret = buf_alloc(dbufp, sizeof(struct v9fs_stat));
397
398 if (ret) {
399 int n = deserialize_stat(bufp, ret, dbufp, extended);
400 if (n <= 0)
401 return NULL;
402 }
403
404 return ret;
405} 309}
406 310
407/** 311/**
@@ -409,194 +313,27 @@ static inline struct v9fs_stat *deserialize_statb(struct cbuf *bufp,
409 * @buf: buffer to deserialize 313 * @buf: buffer to deserialize
410 * @buflen: length of received buffer 314 * @buflen: length of received buffer
411 * @stat: metadata structure to decode into 315 * @stat: metadata structure to decode into
412 * @statlen: length of destination metadata structure
413 * @extended: non-zero if 9P2000.u 316 * @extended: non-zero if 9P2000.u
414 * 317 *
318 * Note: stat will point to the buf region.
415 */ 319 */
416 320
417int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, 321int
418 u32 statlen, int extended) 322v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
323 int extended)
419{ 324{
420 struct cbuf buffer; 325 struct cbuf buffer;
421 struct cbuf *bufp = &buffer; 326 struct cbuf *bufp = &buffer;
422 struct cbuf dbuffer; 327 unsigned char *p;
423 struct cbuf *dbufp = &dbuffer;
424 328
425 buf_init(bufp, buf, buflen); 329 buf_init(bufp, buf, buflen);
426 buf_init(dbufp, (char *)stat + sizeof(struct v9fs_stat), 330 p = bufp->p;
427 statlen - sizeof(struct v9fs_stat)); 331 buf_get_stat(bufp, stat, extended);
428
429 return deserialize_stat(bufp, stat, dbufp, extended);
430}
431
432static inline int v9fs_size_fcall(struct v9fs_fcall *fcall, int extended)
433{
434 int size = 4 + 1 + 2; /* size[4] msg[1] tag[2] */
435 int i = 0;
436 332
437 switch (fcall->id) { 333 if (buf_check_overflow(bufp))
438 default:
439 eprintk(KERN_ERR, "bad msg type %d\n", fcall->id);
440 return 0; 334 return 0;
441 case TVERSION: /* msize[4] version[s] */ 335 else
442 size += 4 + 2 + strlen(fcall->params.tversion.version); 336 return bufp->p - p;
443 break;
444 case TAUTH: /* afid[4] uname[s] aname[s] */
445 size += 4 + 2 + strlen(fcall->params.tauth.uname) +
446 2 + strlen(fcall->params.tauth.aname);
447 break;
448 case TFLUSH: /* oldtag[2] */
449 size += 2;
450 break;
451 case TATTACH: /* fid[4] afid[4] uname[s] aname[s] */
452 size += 4 + 4 + 2 + strlen(fcall->params.tattach.uname) +
453 2 + strlen(fcall->params.tattach.aname);
454 break;
455 case TWALK: /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
456 size += 4 + 4 + 2;
457 /* now compute total for the array of names */
458 for (i = 0; i < fcall->params.twalk.nwname; i++)
459 size += 2 + strlen(fcall->params.twalk.wnames[i]);
460 break;
461 case TOPEN: /* fid[4] mode[1] */
462 size += 4 + 1;
463 break;
464 case TCREATE: /* fid[4] name[s] perm[4] mode[1] */
465 size += 4 + 2 + strlen(fcall->params.tcreate.name) + 4 + 1;
466 break;
467 case TREAD: /* fid[4] offset[8] count[4] */
468 size += 4 + 8 + 4;
469 break;
470 case TWRITE: /* fid[4] offset[8] count[4] data[count] */
471 size += 4 + 8 + 4 + fcall->params.twrite.count;
472 break;
473 case TCLUNK: /* fid[4] */
474 size += 4;
475 break;
476 case TREMOVE: /* fid[4] */
477 size += 4;
478 break;
479 case TSTAT: /* fid[4] */
480 size += 4;
481 break;
482 case TWSTAT: /* fid[4] stat[n] */
483 fcall->params.twstat.stat->size =
484 v9fs_size_stat(fcall->params.twstat.stat, extended);
485 size += 4 + 2 + 2 + fcall->params.twstat.stat->size;
486 }
487 return size;
488}
489
490/*
491 * v9fs_serialize_fcall - marshall fcall struct into a packet
492 * @fcall: structure to convert
493 * @data: buffer to serialize fcall into
494 * @datalen: length of buffer to serialize fcall into
495 * @extended: non-zero if 9P2000.u
496 *
497 */
498
499int
500v9fs_serialize_fcall(struct v9fs_fcall *fcall, void *data, u32 datalen,
501 int extended)
502{
503 int i = 0;
504 struct v9fs_stat *stat = NULL;
505 struct cbuf buffer;
506 struct cbuf *bufp = &buffer;
507
508 buf_init(bufp, data, datalen);
509
510 if (!fcall) {
511 eprintk(KERN_ERR, "no fcall\n");
512 return -EINVAL;
513 }
514
515 fcall->size = v9fs_size_fcall(fcall, extended);
516
517 buf_put_int32(bufp, fcall->size);
518 buf_put_int8(bufp, fcall->id);
519 buf_put_int16(bufp, fcall->tag);
520
521 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", fcall->size, fcall->id,
522 fcall->tag);
523
524 /* now encode it */
525 switch (fcall->id) {
526 default:
527 eprintk(KERN_ERR, "bad msg type: %d\n", fcall->id);
528 return -EPROTO;
529 case TVERSION:
530 buf_put_int32(bufp, fcall->params.tversion.msize);
531 buf_put_string(bufp, fcall->params.tversion.version);
532 break;
533 case TAUTH:
534 buf_put_int32(bufp, fcall->params.tauth.afid);
535 buf_put_string(bufp, fcall->params.tauth.uname);
536 buf_put_string(bufp, fcall->params.tauth.aname);
537 break;
538 case TFLUSH:
539 buf_put_int16(bufp, fcall->params.tflush.oldtag);
540 break;
541 case TATTACH:
542 buf_put_int32(bufp, fcall->params.tattach.fid);
543 buf_put_int32(bufp, fcall->params.tattach.afid);
544 buf_put_string(bufp, fcall->params.tattach.uname);
545 buf_put_string(bufp, fcall->params.tattach.aname);
546 break;
547 case TWALK:
548 buf_put_int32(bufp, fcall->params.twalk.fid);
549 buf_put_int32(bufp, fcall->params.twalk.newfid);
550 buf_put_int16(bufp, fcall->params.twalk.nwname);
551 for (i = 0; i < fcall->params.twalk.nwname; i++)
552 buf_put_string(bufp, fcall->params.twalk.wnames[i]);
553 break;
554 case TOPEN:
555 buf_put_int32(bufp, fcall->params.topen.fid);
556 buf_put_int8(bufp, fcall->params.topen.mode);
557 break;
558 case TCREATE:
559 buf_put_int32(bufp, fcall->params.tcreate.fid);
560 buf_put_string(bufp, fcall->params.tcreate.name);
561 buf_put_int32(bufp, fcall->params.tcreate.perm);
562 buf_put_int8(bufp, fcall->params.tcreate.mode);
563 break;
564 case TREAD:
565 buf_put_int32(bufp, fcall->params.tread.fid);
566 buf_put_int64(bufp, fcall->params.tread.offset);
567 buf_put_int32(bufp, fcall->params.tread.count);
568 break;
569 case TWRITE:
570 buf_put_int32(bufp, fcall->params.twrite.fid);
571 buf_put_int64(bufp, fcall->params.twrite.offset);
572 buf_put_int32(bufp, fcall->params.twrite.count);
573 buf_put_data(bufp, fcall->params.twrite.data,
574 fcall->params.twrite.count);
575 break;
576 case TCLUNK:
577 buf_put_int32(bufp, fcall->params.tclunk.fid);
578 break;
579 case TREMOVE:
580 buf_put_int32(bufp, fcall->params.tremove.fid);
581 break;
582 case TSTAT:
583 buf_put_int32(bufp, fcall->params.tstat.fid);
584 break;
585 case TWSTAT:
586 buf_put_int32(bufp, fcall->params.twstat.fid);
587 stat = fcall->params.twstat.stat;
588
589 buf_put_int16(bufp, stat->size + 2);
590 serialize_stat(stat, bufp, extended);
591 break;
592 }
593
594 if (buf_check_overflow(bufp)) {
595 dprintk(DEBUG_ERROR, "buffer overflow\n");
596 return -EIO;
597 }
598
599 return fcall->size;
600} 337}
601 338
602/** 339/**
@@ -611,18 +348,14 @@ v9fs_serialize_fcall(struct v9fs_fcall *fcall, void *data, u32 datalen,
611 348
612int 349int
613v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, 350v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
614 int rcalllen, int extended) 351 int extended)
615{ 352{
616 353
617 struct cbuf buffer; 354 struct cbuf buffer;
618 struct cbuf *bufp = &buffer; 355 struct cbuf *bufp = &buffer;
619 struct cbuf dbuffer;
620 struct cbuf *dbufp = &dbuffer;
621 int i = 0; 356 int i = 0;
622 357
623 buf_init(bufp, buf, buflen); 358 buf_init(bufp, buf, buflen);
624 buf_init(dbufp, (char *)rcall + sizeof(struct v9fs_fcall),
625 rcalllen - sizeof(struct v9fs_fcall));
626 359
627 rcall->size = buf_get_int32(bufp); 360 rcall->size = buf_get_int32(bufp);
628 rcall->id = buf_get_int8(bufp); 361 rcall->id = buf_get_int8(bufp);
@@ -630,13 +363,14 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
630 363
631 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, 364 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
632 rcall->tag); 365 rcall->tag);
366
633 switch (rcall->id) { 367 switch (rcall->id) {
634 default: 368 default:
635 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); 369 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
636 return -EPROTO; 370 return -EPROTO;
637 case RVERSION: 371 case RVERSION:
638 rcall->params.rversion.msize = buf_get_int32(bufp); 372 rcall->params.rversion.msize = buf_get_int32(bufp);
639 rcall->params.rversion.version = buf_get_stringb(bufp, dbufp); 373 buf_get_str(bufp, &rcall->params.rversion.version);
640 break; 374 break;
641 case RFLUSH: 375 case RFLUSH:
642 break; 376 break;
@@ -647,40 +381,27 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
647 break; 381 break;
648 case RWALK: 382 case RWALK:
649 rcall->params.rwalk.nwqid = buf_get_int16(bufp); 383 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
650 if (rcall->params.rwalk.nwqid > 16) { 384 if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
651 eprintk(KERN_ERR, "Rwalk with more than 16 qids: %d\n", 385 eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
652 rcall->params.rwalk.nwqid); 386 V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
653 return -EPROTO; 387 return -EPROTO;
654 } 388 }
655 389
656 rcall->params.rwalk.wqids = buf_alloc(dbufp, 390 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
657 rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); 391 buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
658 if (rcall->params.rwalk.wqids)
659 for (i = 0; i < rcall->params.rwalk.nwqid; i++) {
660 rcall->params.rwalk.wqids[i].type =
661 buf_get_int8(bufp);
662 rcall->params.rwalk.wqids[i].version =
663 buf_get_int16(bufp);
664 rcall->params.rwalk.wqids[i].path =
665 buf_get_int64(bufp);
666 }
667 break; 392 break;
668 case ROPEN: 393 case ROPEN:
669 rcall->params.ropen.qid.type = buf_get_int8(bufp); 394 buf_get_qid(bufp, &rcall->params.ropen.qid);
670 rcall->params.ropen.qid.version = buf_get_int32(bufp);
671 rcall->params.ropen.qid.path = buf_get_int64(bufp);
672 rcall->params.ropen.iounit = buf_get_int32(bufp); 395 rcall->params.ropen.iounit = buf_get_int32(bufp);
673 break; 396 break;
674 case RCREATE: 397 case RCREATE:
675 rcall->params.rcreate.qid.type = buf_get_int8(bufp); 398 buf_get_qid(bufp, &rcall->params.rcreate.qid);
676 rcall->params.rcreate.qid.version = buf_get_int32(bufp);
677 rcall->params.rcreate.qid.path = buf_get_int64(bufp);
678 rcall->params.rcreate.iounit = buf_get_int32(bufp); 399 rcall->params.rcreate.iounit = buf_get_int32(bufp);
679 break; 400 break;
680 case RREAD: 401 case RREAD:
681 rcall->params.rread.count = buf_get_int32(bufp); 402 rcall->params.rread.count = buf_get_int32(bufp);
682 rcall->params.rread.data = buf_get_datab(bufp, dbufp, 403 rcall->params.rread.data = bufp->p;
683 rcall->params.rread.count); 404 buf_check_size(bufp, rcall->params.rread.count);
684 break; 405 break;
685 case RWRITE: 406 case RWRITE:
686 rcall->params.rwrite.count = buf_get_int32(bufp); 407 rcall->params.rwrite.count = buf_get_int32(bufp);
@@ -691,22 +412,442 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
691 break; 412 break;
692 case RSTAT: 413 case RSTAT:
693 buf_get_int16(bufp); 414 buf_get_int16(bufp);
694 rcall->params.rstat.stat = 415 buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
695 deserialize_statb(bufp, dbufp, extended);
696 break; 416 break;
697 case RWSTAT: 417 case RWSTAT:
698 break; 418 break;
699 case RERROR: 419 case RERROR:
700 rcall->params.rerror.error = buf_get_stringb(bufp, dbufp); 420 buf_get_str(bufp, &rcall->params.rerror.error);
701 if (extended) 421 if (extended)
702 rcall->params.rerror.errno = buf_get_int16(bufp); 422 rcall->params.rerror.errno = buf_get_int16(bufp);
703 break; 423 break;
704 } 424 }
705 425
706 if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) { 426 if (buf_check_overflow(bufp)) {
707 dprintk(DEBUG_ERROR, "buffer overflow\n"); 427 dprintk(DEBUG_ERROR, "buffer overflow\n");
708 return -EIO; 428 return -EIO;
709 } 429 }
710 430
711 return rcall->size; 431 return bufp->p - bufp->sp;
432}
433
434static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
435{
436 *p = val;
437 buf_put_int8(bufp, val);
438}
439
440static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
441{
442 *p = val;
443 buf_put_int16(bufp, val);
444}
445
446static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
447{
448 *p = val;
449 buf_put_int32(bufp, val);
450}
451
452static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
453{
454 *p = val;
455 buf_put_int64(bufp, val);
456}
457
458static inline void
459v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
460{
461 if (data) {
462 str->len = strlen(data);
463 str->str = bufp->p;
464 } else {
465 str->len = 0;
466 str->str = NULL;
467 }
468
469 buf_put_stringn(bufp, data, str->len);
470}
471
472static inline int
473v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
474 unsigned char **pdata)
475{
476 *pdata = buf_alloc(bufp, count);
477 return copy_from_user(*pdata, data, count);
478}
479
480static void
481v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
482 struct v9fs_stat *stat, int statsz, int extended)
483{
484 v9fs_put_int16(bufp, statsz, &stat->size);
485 v9fs_put_int16(bufp, wstat->type, &stat->type);
486 v9fs_put_int32(bufp, wstat->dev, &stat->dev);
487 v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
488 v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
489 v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
490 v9fs_put_int32(bufp, wstat->mode, &stat->mode);
491 v9fs_put_int32(bufp, wstat->atime, &stat->atime);
492 v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
493 v9fs_put_int64(bufp, wstat->length, &stat->length);
494
495 v9fs_put_str(bufp, wstat->name, &stat->name);
496 v9fs_put_str(bufp, wstat->uid, &stat->uid);
497 v9fs_put_str(bufp, wstat->gid, &stat->gid);
498 v9fs_put_str(bufp, wstat->muid, &stat->muid);
499
500 if (extended) {
501 v9fs_put_str(bufp, wstat->extension, &stat->extension);
502 v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
503 v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
504 v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
505 }
506}
507
508static struct v9fs_fcall *
509v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
510{
511 struct v9fs_fcall *fc;
512
513 size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
514 fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
515 if (!fc)
516 return ERR_PTR(-ENOMEM);
517
518 fc->sdata = (char *)fc + sizeof(*fc);
519
520 buf_init(bufp, (char *)fc->sdata, size);
521 v9fs_put_int32(bufp, size, &fc->size);
522 v9fs_put_int8(bufp, id, &fc->id);
523 v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
524
525 return fc;
526}
527
528void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
529{
530 *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
531}
532
533struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
534{
535 int size;
536 struct v9fs_fcall *fc;
537 struct cbuf buffer;
538 struct cbuf *bufp = &buffer;
539
540 size = 4 + 2 + strlen(version); /* msize[4] version[s] */
541 fc = v9fs_create_common(bufp, size, TVERSION);
542 if (IS_ERR(fc))
543 goto error;
544
545 v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
546 v9fs_put_str(bufp, version, &fc->params.tversion.version);
547
548 if (buf_check_overflow(bufp)) {
549 kfree(fc);
550 fc = ERR_PTR(-ENOMEM);
551 }
552 error:
553 return fc;
554}
555
556struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
557{
558 int size;
559 struct v9fs_fcall *fc;
560 struct cbuf buffer;
561 struct cbuf *bufp = &buffer;
562
563 size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */
564 fc = v9fs_create_common(bufp, size, TAUTH);
565 if (IS_ERR(fc))
566 goto error;
567
568 v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
569 v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
570 v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
571
572 if (buf_check_overflow(bufp)) {
573 kfree(fc);
574 fc = ERR_PTR(-ENOMEM);
575 }
576 error:
577 return fc;
578}
579
580struct v9fs_fcall *
581v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
582{
583 int size;
584 struct v9fs_fcall *fc;
585 struct cbuf buffer;
586 struct cbuf *bufp = &buffer;
587
588 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */
589 fc = v9fs_create_common(bufp, size, TATTACH);
590 if (IS_ERR(fc))
591 goto error;
592
593 v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
594 v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
595 v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
596 v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
597
598 error:
599 return fc;
600}
601
602struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
603{
604 int size;
605 struct v9fs_fcall *fc;
606 struct cbuf buffer;
607 struct cbuf *bufp = &buffer;
608
609 size = 2; /* oldtag[2] */
610 fc = v9fs_create_common(bufp, size, TFLUSH);
611 if (IS_ERR(fc))
612 goto error;
613
614 v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
615
616 if (buf_check_overflow(bufp)) {
617 kfree(fc);
618 fc = ERR_PTR(-ENOMEM);
619 }
620 error:
621 return fc;
622}
623
624struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
625 char **wnames)
626{
627 int i, size;
628 struct v9fs_fcall *fc;
629 struct cbuf buffer;
630 struct cbuf *bufp = &buffer;
631
632 if (nwname > V9FS_MAXWELEM) {
633 dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
634 return NULL;
635 }
636
637 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
638 for (i = 0; i < nwname; i++) {
639 size += 2 + strlen(wnames[i]); /* wname[s] */
640 }
641
642 fc = v9fs_create_common(bufp, size, TWALK);
643 if (IS_ERR(fc))
644 goto error;
645
646 v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
647 v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
648 v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
649 for (i = 0; i < nwname; i++) {
650 v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
651 }
652
653 if (buf_check_overflow(bufp)) {
654 kfree(fc);
655 fc = ERR_PTR(-ENOMEM);
656 }
657 error:
658 return fc;
659}
660
661struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
662{
663 int size;
664 struct v9fs_fcall *fc;
665 struct cbuf buffer;
666 struct cbuf *bufp = &buffer;
667
668 size = 4 + 1; /* fid[4] mode[1] */
669 fc = v9fs_create_common(bufp, size, TOPEN);
670 if (IS_ERR(fc))
671 goto error;
672
673 v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
674 v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
675
676 if (buf_check_overflow(bufp)) {
677 kfree(fc);
678 fc = ERR_PTR(-ENOMEM);
679 }
680 error:
681 return fc;
682}
683
684struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode)
685{
686 int size;
687 struct v9fs_fcall *fc;
688 struct cbuf buffer;
689 struct cbuf *bufp = &buffer;
690
691 size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */
692 fc = v9fs_create_common(bufp, size, TCREATE);
693 if (IS_ERR(fc))
694 goto error;
695
696 v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
697 v9fs_put_str(bufp, name, &fc->params.tcreate.name);
698 v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
699 v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
700
701 if (buf_check_overflow(bufp)) {
702 kfree(fc);
703 fc = ERR_PTR(-ENOMEM);
704 }
705 error:
706 return fc;
707}
708
709struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
710{
711 int size;
712 struct v9fs_fcall *fc;
713 struct cbuf buffer;
714 struct cbuf *bufp = &buffer;
715
716 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
717 fc = v9fs_create_common(bufp, size, TREAD);
718 if (IS_ERR(fc))
719 goto error;
720
721 v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
722 v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
723 v9fs_put_int32(bufp, count, &fc->params.tread.count);
724
725 if (buf_check_overflow(bufp)) {
726 kfree(fc);
727 fc = ERR_PTR(-ENOMEM);
728 }
729 error:
730 return fc;
731}
732
733struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
734 const char __user * data)
735{
736 int size, err;
737 struct v9fs_fcall *fc;
738 struct cbuf buffer;
739 struct cbuf *bufp = &buffer;
740
741 size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */
742 fc = v9fs_create_common(bufp, size, TWRITE);
743 if (IS_ERR(fc))
744 goto error;
745
746 v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
747 v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
748 v9fs_put_int32(bufp, count, &fc->params.twrite.count);
749 err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
750 if (err) {
751 kfree(fc);
752 fc = ERR_PTR(err);
753 }
754
755 if (buf_check_overflow(bufp)) {
756 kfree(fc);
757 fc = ERR_PTR(-ENOMEM);
758 }
759 error:
760 return fc;
761}
762
763struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
764{
765 int size;
766 struct v9fs_fcall *fc;
767 struct cbuf buffer;
768 struct cbuf *bufp = &buffer;
769
770 size = 4; /* fid[4] */
771 fc = v9fs_create_common(bufp, size, TCLUNK);
772 if (IS_ERR(fc))
773 goto error;
774
775 v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
776
777 if (buf_check_overflow(bufp)) {
778 kfree(fc);
779 fc = ERR_PTR(-ENOMEM);
780 }
781 error:
782 return fc;
783}
784
785struct v9fs_fcall *v9fs_create_tremove(u32 fid)
786{
787 int size;
788 struct v9fs_fcall *fc;
789 struct cbuf buffer;
790 struct cbuf *bufp = &buffer;
791
792 size = 4; /* fid[4] */
793 fc = v9fs_create_common(bufp, size, TREMOVE);
794 if (IS_ERR(fc))
795 goto error;
796
797 v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
798
799 if (buf_check_overflow(bufp)) {
800 kfree(fc);
801 fc = ERR_PTR(-ENOMEM);
802 }
803 error:
804 return fc;
805}
806
807struct v9fs_fcall *v9fs_create_tstat(u32 fid)
808{
809 int size;
810 struct v9fs_fcall *fc;
811 struct cbuf buffer;
812 struct cbuf *bufp = &buffer;
813
814 size = 4; /* fid[4] */
815 fc = v9fs_create_common(bufp, size, TSTAT);
816 if (IS_ERR(fc))
817 goto error;
818
819 v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
820
821 if (buf_check_overflow(bufp)) {
822 kfree(fc);
823 fc = ERR_PTR(-ENOMEM);
824 }
825 error:
826 return fc;
827}
828
829struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
830 int extended)
831{
832 int size, statsz;
833 struct v9fs_fcall *fc;
834 struct cbuf buffer;
835 struct cbuf *bufp = &buffer;
836
837 statsz = v9fs_size_wstat(wstat, extended);
838 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
839 fc = v9fs_create_common(bufp, size, TWSTAT);
840 if (IS_ERR(fc))
841 goto error;
842
843 v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
844 buf_put_int16(bufp, statsz + 2);
845 v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
846
847 if (buf_check_overflow(bufp)) {
848 kfree(fc);
849 fc = ERR_PTR(-ENOMEM);
850 }
851 error:
852 return fc;
712} 853}
diff --git a/fs/9p/conv.h b/fs/9p/conv.h
index d5e33e17a685..26a736e4a2e7 100644
--- a/fs/9p/conv.h
+++ b/fs/9p/conv.h
@@ -1,8 +1,9 @@
1/* 1/*
2 * linux/fs/9p/conv.h 2 * linux/fs/9p/conv.h
3 * 3 *
4 * 9P protocol conversion definitions 4 * 9P protocol conversion definitions.
5 * 5 *
6 * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8 * 9 *
@@ -25,11 +26,26 @@
25 */ 26 */
26 27
27int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, 28int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
28 u32 statlen, int extended);
29int v9fs_serialize_fcall(struct v9fs_fcall *tcall, void *buf, u32 buflen,
30 int extended); 29 int extended);
31int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, 30int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
32 int rcalllen, int extended); 31 int extended);
32
33void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag);
33 34
34/* this one is actually in error.c right now */ 35struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version);
35int v9fs_errstr2errno(char *errstr); 36struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname);
37struct v9fs_fcall *v9fs_create_tattach(u32 fid, u32 afid, char *uname,
38 char *aname);
39struct v9fs_fcall *v9fs_create_tflush(u16 oldtag);
40struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
41 char **wnames);
42struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode);
43struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode);
44struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count);
45struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
46 const char __user *data);
47struct v9fs_fcall *v9fs_create_tclunk(u32 fid);
48struct v9fs_fcall *v9fs_create_tremove(u32 fid);
49struct v9fs_fcall *v9fs_create_tstat(u32 fid);
50struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
51 int extended);
diff --git a/fs/9p/debug.h b/fs/9p/debug.h
index 4445f06919d9..fe551032788b 100644
--- a/fs/9p/debug.h
+++ b/fs/9p/debug.h
@@ -51,16 +51,23 @@ do { \
51#if DEBUG_DUMP_PKT 51#if DEBUG_DUMP_PKT
52static inline void dump_data(const unsigned char *data, unsigned int datalen) 52static inline void dump_data(const unsigned char *data, unsigned int datalen)
53{ 53{
54 int i, j; 54 int i, n;
55 int len = datalen; 55 char buf[5*8];
56 56
57 printk(KERN_DEBUG "data "); 57 n = 0;
58 for (i = 0; i < len; i += 4) { 58 i = 0;
59 for (j = 0; (j < 4) && (i + j < len); j++) 59 while (i < datalen) {
60 printk(KERN_DEBUG "%02x", data[i + j]); 60 n += snprintf(buf+n, sizeof(buf)-n, "%02x", data[i++]);
61 printk(KERN_DEBUG " "); 61 if (i%4 == 0)
62 n += snprintf(buf+n, sizeof(buf)-n, " ");
63
64 if (i%16 == 0) {
65 dprintk(DEBUG_ERROR, "%s\n", buf);
66 n = 0;
67 }
62 } 68 }
63 printk(KERN_DEBUG "\n"); 69
70 dprintk(DEBUG_ERROR, "%s\n", buf);
64} 71}
65#else /* DEBUG_DUMP_PKT */ 72#else /* DEBUG_DUMP_PKT */
66static inline void dump_data(const unsigned char *data, unsigned int datalen) 73static inline void dump_data(const unsigned char *data, unsigned int datalen)
diff --git a/fs/9p/error.c b/fs/9p/error.c
index 834cb179e388..e4b6f8f38b6f 100644
--- a/fs/9p/error.c
+++ b/fs/9p/error.c
@@ -33,7 +33,6 @@
33 33
34#include <linux/list.h> 34#include <linux/list.h>
35#include <linux/jhash.h> 35#include <linux/jhash.h>
36#include <linux/string.h>
37 36
38#include "debug.h" 37#include "debug.h"
39#include "error.h" 38#include "error.h"
@@ -55,7 +54,8 @@ int v9fs_error_init(void)
55 54
56 /* load initial error map into hash table */ 55 /* load initial error map into hash table */
57 for (c = errmap; c->name != NULL; c++) { 56 for (c = errmap; c->name != NULL; c++) {
58 bucket = jhash(c->name, strlen(c->name), 0) % ERRHASHSZ; 57 c->namelen = strlen(c->name);
58 bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ;
59 INIT_HLIST_NODE(&c->list); 59 INIT_HLIST_NODE(&c->list);
60 hlist_add_head(&c->list, &hash_errmap[bucket]); 60 hlist_add_head(&c->list, &hash_errmap[bucket]);
61 } 61 }
@@ -69,15 +69,15 @@ int v9fs_error_init(void)
69 * 69 *
70 */ 70 */
71 71
72int v9fs_errstr2errno(char *errstr) 72int v9fs_errstr2errno(char *errstr, int len)
73{ 73{
74 int errno = 0; 74 int errno = 0;
75 struct hlist_node *p = NULL; 75 struct hlist_node *p = NULL;
76 struct errormap *c = NULL; 76 struct errormap *c = NULL;
77 int bucket = jhash(errstr, strlen(errstr), 0) % ERRHASHSZ; 77 int bucket = jhash(errstr, len, 0) % ERRHASHSZ;
78 78
79 hlist_for_each_entry(c, p, &hash_errmap[bucket], list) { 79 hlist_for_each_entry(c, p, &hash_errmap[bucket], list) {
80 if (!strcmp(c->name, errstr)) { 80 if (c->namelen==len && !memcmp(c->name, errstr, len)) {
81 errno = c->val; 81 errno = c->val;
82 break; 82 break;
83 } 83 }
diff --git a/fs/9p/error.h b/fs/9p/error.h
index 78f89acf7c9a..8b3176b3f658 100644
--- a/fs/9p/error.h
+++ b/fs/9p/error.h
@@ -36,6 +36,7 @@ struct errormap {
36 char *name; 36 char *name;
37 int val; 37 int val;
38 38
39 int namelen;
39 struct hlist_node list; 40 struct hlist_node list;
40}; 41};
41 42
@@ -175,4 +176,4 @@ static struct errormap errmap[] = {
175}; 176};
176 177
177extern int v9fs_error_init(void); 178extern int v9fs_error_init(void);
178extern int v9fs_errstr2errno(char *errstr); 179extern int v9fs_errstr2errno(char *errstr, int len);
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 60ef8aba757a..eda449778fa5 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -31,9 +31,6 @@
31#include "v9fs.h" 31#include "v9fs.h"
32#include "9p.h" 32#include "9p.h"
33#include "v9fs_vfs.h" 33#include "v9fs_vfs.h"
34#include "transport.h"
35#include "mux.h"
36#include "conv.h"
37#include "fid.h" 34#include "fid.h"
38 35
39/** 36/**
diff --git a/fs/9p/mux.c b/fs/9p/mux.c
index 62b6ad0767e1..f21cf5083973 100644
--- a/fs/9p/mux.c
+++ b/fs/9p/mux.c
@@ -35,8 +35,8 @@
35#include "debug.h" 35#include "debug.h"
36#include "v9fs.h" 36#include "v9fs.h"
37#include "9p.h" 37#include "9p.h"
38#include "transport.h"
39#include "conv.h" 38#include "conv.h"
39#include "transport.h"
40#include "mux.h" 40#include "mux.h"
41 41
42#define ERREQFLUSH 1 42#define ERREQFLUSH 1
@@ -74,6 +74,7 @@ struct v9fs_mux_data {
74 wait_queue_head_t equeue; 74 wait_queue_head_t equeue;
75 struct list_head req_list; 75 struct list_head req_list;
76 struct list_head unsent_req_list; 76 struct list_head unsent_req_list;
77 struct v9fs_fcall *rcall;
77 int rpos; 78 int rpos;
78 char *rbuf; 79 char *rbuf;
79 int wpos; 80 int wpos;
@@ -101,11 +102,15 @@ struct v9fs_mux_rpc {
101 wait_queue_head_t wqueue; 102 wait_queue_head_t wqueue;
102}; 103};
103 104
105extern int v9fs_errstr2errno(char *str, int len);
106
104static int v9fs_poll_proc(void *); 107static int v9fs_poll_proc(void *);
105static void v9fs_read_work(void *); 108static void v9fs_read_work(void *);
106static void v9fs_write_work(void *); 109static void v9fs_write_work(void *);
107static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, 110static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
108 poll_table * p); 111 poll_table * p);
112static u16 v9fs_mux_get_tag(struct v9fs_mux_data *);
113static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16);
109 114
110static DECLARE_MUTEX(v9fs_mux_task_lock); 115static DECLARE_MUTEX(v9fs_mux_task_lock);
111static struct workqueue_struct *v9fs_mux_wq; 116static struct workqueue_struct *v9fs_mux_wq;
@@ -166,8 +171,9 @@ static void v9fs_mux_poll_start(struct v9fs_mux_data *m)
166 if (v9fs_mux_poll_tasks[i].task == NULL) { 171 if (v9fs_mux_poll_tasks[i].task == NULL) {
167 vpt = &v9fs_mux_poll_tasks[i]; 172 vpt = &v9fs_mux_poll_tasks[i];
168 dprintk(DEBUG_MUX, "create proc %p\n", vpt); 173 dprintk(DEBUG_MUX, "create proc %p\n", vpt);
169 vpt->task = kthread_create(v9fs_poll_proc, 174 vpt->task =
170 vpt, "v9fs-poll"); 175 kthread_create(v9fs_poll_proc, vpt,
176 "v9fs-poll");
171 INIT_LIST_HEAD(&vpt->mux_list); 177 INIT_LIST_HEAD(&vpt->mux_list);
172 vpt->muxnum = 0; 178 vpt->muxnum = 0;
173 v9fs_mux_poll_task_num++; 179 v9fs_mux_poll_task_num++;
@@ -253,7 +259,7 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
253 struct v9fs_mux_data *m, *mtmp; 259 struct v9fs_mux_data *m, *mtmp;
254 260
255 dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize); 261 dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize);
256 m = kmalloc(sizeof(struct v9fs_mux_data) + 2 * msize, GFP_KERNEL); 262 m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL);
257 if (!m) 263 if (!m)
258 return ERR_PTR(-ENOMEM); 264 return ERR_PTR(-ENOMEM);
259 265
@@ -268,10 +274,11 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
268 init_waitqueue_head(&m->equeue); 274 init_waitqueue_head(&m->equeue);
269 INIT_LIST_HEAD(&m->req_list); 275 INIT_LIST_HEAD(&m->req_list);
270 INIT_LIST_HEAD(&m->unsent_req_list); 276 INIT_LIST_HEAD(&m->unsent_req_list);
277 m->rcall = NULL;
271 m->rpos = 0; 278 m->rpos = 0;
272 m->rbuf = (char *)m + sizeof(struct v9fs_mux_data); 279 m->rbuf = NULL;
273 m->wpos = m->wsize = 0; 280 m->wpos = m->wsize = 0;
274 m->wbuf = m->rbuf + msize; 281 m->wbuf = NULL;
275 INIT_WORK(&m->rq, v9fs_read_work, m); 282 INIT_WORK(&m->rq, v9fs_read_work, m);
276 INIT_WORK(&m->wq, v9fs_write_work, m); 283 INIT_WORK(&m->wq, v9fs_write_work, m);
277 m->wsched = 0; 284 m->wsched = 0;
@@ -427,29 +434,6 @@ static int v9fs_poll_proc(void *a)
427 return 0; 434 return 0;
428} 435}
429 436
430static inline int v9fs_write_req(struct v9fs_mux_data *m, struct v9fs_req *req)
431{
432 int n;
433
434 list_move_tail(&req->req_list, &m->req_list);
435 n = v9fs_serialize_fcall(req->tcall, m->wbuf, m->msize, *m->extended);
436 if (n < 0) {
437 req->err = n;
438 list_del(&req->req_list);
439 if (req->cb) {
440 spin_unlock(&m->lock);
441 (*req->cb) (req->cba, req->tcall, req->rcall, req->err);
442 req->cb = NULL;
443 spin_lock(&m->lock);
444 } else
445 kfree(req->rcall);
446
447 kfree(req);
448 }
449
450 return n;
451}
452
453/** 437/**
454 * v9fs_write_work - called when a transport can send some data 438 * v9fs_write_work - called when a transport can send some data
455 */ 439 */
@@ -457,7 +441,7 @@ static void v9fs_write_work(void *a)
457{ 441{
458 int n, err; 442 int n, err;
459 struct v9fs_mux_data *m; 443 struct v9fs_mux_data *m;
460 struct v9fs_req *req, *rtmp; 444 struct v9fs_req *req;
461 445
462 m = a; 446 m = a;
463 447
@@ -472,17 +456,15 @@ static void v9fs_write_work(void *a)
472 return; 456 return;
473 } 457 }
474 458
475 err = 0;
476 spin_lock(&m->lock); 459 spin_lock(&m->lock);
477 list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, 460 req =
478 req_list) { 461 list_entry(m->unsent_req_list.next, struct v9fs_req,
479 err = v9fs_write_req(m, req); 462 req_list);
480 if (err > 0) 463 list_move_tail(&req->req_list, &m->req_list);
481 break; 464 m->wbuf = req->tcall->sdata;
482 } 465 m->wsize = req->tcall->size;
483
484 m->wsize = err;
485 m->wpos = 0; 466 m->wpos = 0;
467 dump_data(m->wbuf, m->wsize);
486 spin_unlock(&m->lock); 468 spin_unlock(&m->lock);
487 } 469 }
488 470
@@ -526,24 +508,23 @@ static void v9fs_write_work(void *a)
526static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) 508static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
527{ 509{
528 int ecode, tag; 510 int ecode, tag;
529 char *ename; 511 struct v9fs_str *ename;
530 512
531 tag = req->tag; 513 tag = req->tag;
532 if (req->rcall->id == RERROR && !req->err) { 514 if (req->rcall->id == RERROR && !req->err) {
533 ecode = req->rcall->params.rerror.errno; 515 ecode = req->rcall->params.rerror.errno;
534 ename = req->rcall->params.rerror.error; 516 ename = &req->rcall->params.rerror.error;
535 517
536 dprintk(DEBUG_MUX, "Rerror %s\n", ename); 518 dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str);
537 519
538 if (*m->extended) 520 if (*m->extended)
539 req->err = -ecode; 521 req->err = -ecode;
540 522
541 if (!req->err) { 523 if (!req->err) {
542 req->err = v9fs_errstr2errno(ename); 524 req->err = v9fs_errstr2errno(ename->str, ename->len);
543 525
544 if (!req->err) { /* string match failed */ 526 if (!req->err) { /* string match failed */
545 dprintk(DEBUG_ERROR, "unknown error: %s\n", 527 PRINT_FCALL_ERROR("unknown error", req->rcall);
546 ename);
547 } 528 }
548 529
549 if (!req->err) 530 if (!req->err)
@@ -565,8 +546,7 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
565 } else 546 } else
566 kfree(req->rcall); 547 kfree(req->rcall);
567 548
568 if (tag != V9FS_NOTAG) 549 v9fs_mux_put_tag(m, tag);
569 v9fs_put_idpool(tag, &m->tidpool);
570 550
571 wake_up(&m->equeue); 551 wake_up(&m->equeue);
572 kfree(req); 552 kfree(req);
@@ -577,10 +557,11 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
577 */ 557 */
578static void v9fs_read_work(void *a) 558static void v9fs_read_work(void *a)
579{ 559{
580 int n, err, rcallen; 560 int n, err;
581 struct v9fs_mux_data *m; 561 struct v9fs_mux_data *m;
582 struct v9fs_req *req, *rptr, *rreq; 562 struct v9fs_req *req, *rptr, *rreq;
583 struct v9fs_fcall *rcall; 563 struct v9fs_fcall *rcall;
564 char *rbuf;
584 565
585 m = a; 566 m = a;
586 567
@@ -589,6 +570,19 @@ static void v9fs_read_work(void *a)
589 570
590 rcall = NULL; 571 rcall = NULL;
591 dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); 572 dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
573
574 if (!m->rcall) {
575 m->rcall =
576 kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL);
577 if (!m->rcall) {
578 err = -ENOMEM;
579 goto error;
580 }
581
582 m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
583 m->rpos = 0;
584 }
585
592 clear_bit(Rpending, &m->wsched); 586 clear_bit(Rpending, &m->wsched);
593 err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); 587 err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
594 dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err); 588 dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err);
@@ -613,21 +607,32 @@ static void v9fs_read_work(void *a)
613 if (m->rpos < n) 607 if (m->rpos < n)
614 break; 608 break;
615 609
616 rcallen = n + V9FS_FCALLHDRSZ;
617 rcall = kmalloc(rcallen, GFP_KERNEL);
618 if (!rcall) {
619 err = -ENOMEM;
620 goto error;
621 }
622
623 dump_data(m->rbuf, n); 610 dump_data(m->rbuf, n);
624 err = v9fs_deserialize_fcall(m->rbuf, n, rcall, rcallen, 611 err =
625 *m->extended); 612 v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
626 if (err < 0) { 613 if (err < 0) {
627 kfree(rcall);
628 goto error; 614 goto error;
629 } 615 }
630 616
617 rcall = m->rcall;
618 rbuf = m->rbuf;
619 if (m->rpos > n) {
620 m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize,
621 GFP_KERNEL);
622 if (!m->rcall) {
623 err = -ENOMEM;
624 goto error;
625 }
626
627 m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
628 memmove(m->rbuf, rbuf + n, m->rpos - n);
629 m->rpos -= n;
630 } else {
631 m->rcall = NULL;
632 m->rbuf = NULL;
633 m->rpos = 0;
634 }
635
631 dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id, 636 dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id,
632 rcall->tag); 637 rcall->tag);
633 638
@@ -642,6 +647,7 @@ static void v9fs_read_work(void *a)
642 process_request(m, req); 647 process_request(m, req);
643 break; 648 break;
644 } 649 }
650
645 } 651 }
646 652
647 if (!req) { 653 if (!req) {
@@ -652,10 +658,6 @@ static void v9fs_read_work(void *a)
652 m, rcall->id, rcall->tag); 658 m, rcall->id, rcall->tag);
653 kfree(rcall); 659 kfree(rcall);
654 } 660 }
655
656 if (m->rpos > n)
657 memmove(m->rbuf, m->rbuf + n, m->rpos - n);
658 m->rpos -= n;
659 } 661 }
660 662
661 if (!list_empty(&m->req_list)) { 663 if (!list_empty(&m->req_list)) {
@@ -710,12 +712,13 @@ static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m,
710 if (tc->id == TVERSION) 712 if (tc->id == TVERSION)
711 n = V9FS_NOTAG; 713 n = V9FS_NOTAG;
712 else 714 else
713 n = v9fs_get_idpool(&m->tidpool); 715 n = v9fs_mux_get_tag(m);
714 716
715 if (n < 0) 717 if (n < 0)
716 return ERR_PTR(-ENOMEM); 718 return ERR_PTR(-ENOMEM);
717 719
718 tc->tag = n; 720 v9fs_set_tag(tc, n);
721
719 req->tag = n; 722 req->tag = n;
720 req->tcall = tc; 723 req->tcall = tc;
721 req->rcall = NULL; 724 req->rcall = NULL;
@@ -773,9 +776,7 @@ v9fs_mux_flush_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc,
773 if (!cb) 776 if (!cb)
774 spin_unlock(&m->lock); 777 spin_unlock(&m->lock);
775 778
776 if (v9fs_check_idpool(tag, &m->tidpool)) 779 v9fs_mux_put_tag(m, tag);
777 v9fs_put_idpool(tag, &m->tidpool);
778
779 kfree(tc); 780 kfree(tc);
780 kfree(rc); 781 kfree(rc);
781} 782}
@@ -787,10 +788,7 @@ v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req)
787 788
788 dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); 789 dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
789 790
790 fc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL); 791 fc = v9fs_create_tflush(req->tag);
791 fc->id = TFLUSH;
792 fc->params.tflush.oldtag = req->tag;
793
794 v9fs_send_request(m, fc, v9fs_mux_flush_cb, m); 792 v9fs_send_request(m, fc, v9fs_mux_flush_cb, m);
795} 793}
796 794
@@ -939,3 +937,20 @@ void v9fs_mux_cancel(struct v9fs_mux_data *m, int err)
939 937
940 wake_up(&m->equeue); 938 wake_up(&m->equeue);
941} 939}
940
941static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m)
942{
943 int tag;
944
945 tag = v9fs_get_idpool(&m->tidpool);
946 if (tag < 0)
947 return V9FS_NOTAG;
948 else
949 return (u16) tag;
950}
951
952static void v9fs_mux_put_tag(struct v9fs_mux_data *m, u16 tag)
953{
954 if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tidpool))
955 v9fs_put_idpool(tag, &m->tidpool);
956}
diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c
index 9ef404c75c8f..44e830697acb 100644
--- a/fs/9p/trans_sock.c
+++ b/fs/9p/trans_sock.c
@@ -110,7 +110,6 @@ static int v9fs_sock_send(struct v9fs_transport *trans, void *v, int len)
110 if (!(ts->filp->f_flags & O_NONBLOCK)) 110 if (!(ts->filp->f_flags & O_NONBLOCK))
111 dprintk(DEBUG_ERROR, "blocking write ...\n"); 111 dprintk(DEBUG_ERROR, "blocking write ...\n");
112 112
113 dump_data(v, len);
114 oldfs = get_fs(); 113 oldfs = get_fs();
115 set_fs(get_ds()); 114 set_fs(get_ds());
116 ret = vfs_write(ts->filp, (void __user *)v, len, &ts->filp->f_pos); 115 ret = vfs_write(ts->filp, (void __user *)v, len, &ts->filp->f_pos);
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 5e0f79355fdf..519b21d8b15b 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -37,7 +37,6 @@
37#include "v9fs_vfs.h" 37#include "v9fs_vfs.h"
38#include "transport.h" 38#include "transport.h"
39#include "mux.h" 39#include "mux.h"
40#include "conv.h"
41 40
42/* TODO: sysfs or debugfs interface */ 41/* TODO: sysfs or debugfs interface */
43int v9fs_debug_level = 0; /* feature-rific global debug level */ 42int v9fs_debug_level = 0; /* feature-rific global debug level */
@@ -353,7 +352,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
353 } 352 }
354 353
355 /* Really should check for 9P1 and report error */ 354 /* Really should check for 9P1 and report error */
356 if (!strcmp(fcall->params.rversion.version, "9P2000.u")) { 355 if (!v9fs_str_compare("9P2000.u", &fcall->params.rversion.version)) {
357 dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n"); 356 dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n");
358 v9ses->extended = 1; 357 v9ses->extended = 1;
359 } else { 358 } else {
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 2f2cea7ee3e7..c78502ad00ed 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -45,9 +45,8 @@ extern struct dentry_operations v9fs_dentry_operations;
45 45
46struct inode *v9fs_get_inode(struct super_block *sb, int mode); 46struct inode *v9fs_get_inode(struct super_block *sb, int mode);
47ino_t v9fs_qid2ino(struct v9fs_qid *qid); 47ino_t v9fs_qid2ino(struct v9fs_qid *qid);
48void v9fs_mistat2inode(struct v9fs_stat *, struct inode *, 48void v9fs_stat2inode(struct v9fs_stat *, struct inode *, struct super_block *);
49 struct super_block *);
50int v9fs_dir_release(struct inode *inode, struct file *filp); 49int v9fs_dir_release(struct inode *inode, struct file *filp);
51int v9fs_file_open(struct inode *inode, struct file *file); 50int v9fs_file_open(struct inode *inode, struct file *file);
52void v9fs_inode2mistat(struct inode *inode, struct v9fs_stat *mistat); 51void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat);
53void v9fs_dentry_release(struct dentry *); 52void v9fs_dentry_release(struct dentry *);
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index 4887df767394..2dd806dac9f1 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -40,7 +40,6 @@
40#include "v9fs.h" 40#include "v9fs.h"
41#include "9p.h" 41#include "9p.h"
42#include "v9fs_vfs.h" 42#include "v9fs_vfs.h"
43#include "conv.h"
44#include "fid.h" 43#include "fid.h"
45 44
46/** 45/**
@@ -108,7 +107,8 @@ void v9fs_dentry_release(struct dentry *dentry)
108 err = v9fs_t_clunk(current_fid->v9ses, current_fid->fid); 107 err = v9fs_t_clunk(current_fid->v9ses, current_fid->fid);
109 108
110 if (err < 0) 109 if (err < 0)
111 dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); 110 dprintk(DEBUG_ERROR, "clunk failed: %d name %s\n",
111 err, dentry->d_iname);
112 112
113 v9fs_fid_destroy(current_fid); 113 v9fs_fid_destroy(current_fid);
114 } 114 }
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 3893dd307ddb..ae6d032b9b59 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -37,8 +37,8 @@
37#include "debug.h" 37#include "debug.h"
38#include "v9fs.h" 38#include "v9fs.h"
39#include "9p.h" 39#include "9p.h"
40#include "v9fs_vfs.h"
41#include "conv.h" 40#include "conv.h"
41#include "v9fs_vfs.h"
42#include "fid.h" 42#include "fid.h"
43 43
44/** 44/**
@@ -77,17 +77,13 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
77 unsigned int i, n, s; 77 unsigned int i, n, s;
78 int fid = -1; 78 int fid = -1;
79 int ret = 0; 79 int ret = 0;
80 struct v9fs_stat *mi = NULL; 80 struct v9fs_stat stat;
81 int over = 0; 81 int over = 0;
82 82
83 dprintk(DEBUG_VFS, "name %s\n", filp->f_dentry->d_name.name); 83 dprintk(DEBUG_VFS, "name %s\n", filp->f_dentry->d_name.name);
84 84
85 fid = file->fid; 85 fid = file->fid;
86 86
87 mi = kmalloc(v9ses->maxdata, GFP_KERNEL);
88 if (!mi)
89 return -ENOMEM;
90
91 if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) { 87 if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) {
92 kfree(file->rdir_fcall); 88 kfree(file->rdir_fcall);
93 file->rdir_fcall = NULL; 89 file->rdir_fcall = NULL;
@@ -99,18 +95,18 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
99 while (i < n) { 95 while (i < n) {
100 s = v9fs_deserialize_stat( 96 s = v9fs_deserialize_stat(
101 file->rdir_fcall->params.rread.data + i, 97 file->rdir_fcall->params.rread.data + i,
102 n - i, mi, v9ses->maxdata, v9ses->extended); 98 n - i, &stat, v9ses->extended);
103 99
104 if (s == 0) { 100 if (s == 0) {
105 dprintk(DEBUG_ERROR, 101 dprintk(DEBUG_ERROR,
106 "error while deserializing mistat\n"); 102 "error while deserializing stat\n");
107 ret = -EIO; 103 ret = -EIO;
108 goto FreeStructs; 104 goto FreeStructs;
109 } 105 }
110 106
111 over = filldir(dirent, mi->name, strlen(mi->name), 107 over = filldir(dirent, stat.name.str, stat.name.len,
112 filp->f_pos, v9fs_qid2ino(&mi->qid), 108 filp->f_pos, v9fs_qid2ino(&stat.qid),
113 dt_type(mi)); 109 dt_type(&stat));
114 110
115 if (over) { 111 if (over) {
116 file->rdir_fpos = i; 112 file->rdir_fpos = i;
@@ -130,7 +126,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
130 126
131 while (!over) { 127 while (!over) {
132 ret = v9fs_t_read(v9ses, fid, filp->f_pos, 128 ret = v9fs_t_read(v9ses, fid, filp->f_pos,
133 v9ses->maxdata-V9FS_IOHDRSZ, &fcall); 129 v9ses->maxdata-V9FS_IOHDRSZ, &fcall);
134 if (ret < 0) { 130 if (ret < 0) {
135 dprintk(DEBUG_ERROR, "error while reading: %d: %p\n", 131 dprintk(DEBUG_ERROR, "error while reading: %d: %p\n",
136 ret, fcall); 132 ret, fcall);
@@ -142,17 +138,17 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
142 i = 0; 138 i = 0;
143 while (i < n) { 139 while (i < n) {
144 s = v9fs_deserialize_stat(fcall->params.rread.data + i, 140 s = v9fs_deserialize_stat(fcall->params.rread.data + i,
145 n - i, mi, v9ses->maxdata, v9ses->extended); 141 n - i, &stat, v9ses->extended);
146 142
147 if (s == 0) { 143 if (s == 0) {
148 dprintk(DEBUG_ERROR, 144 dprintk(DEBUG_ERROR,
149 "error while deserializing mistat\n"); 145 "error while deserializing stat\n");
150 return -EIO; 146 return -EIO;
151 } 147 }
152 148
153 over = filldir(dirent, mi->name, strlen(mi->name), 149 over = filldir(dirent, stat.name.str, stat.name.len,
154 filp->f_pos, v9fs_qid2ino(&mi->qid), 150 filp->f_pos, v9fs_qid2ino(&stat.qid),
155 dt_type(mi)); 151 dt_type(&stat));
156 152
157 if (over) { 153 if (over) {
158 file->rdir_fcall = fcall; 154 file->rdir_fcall = fcall;
@@ -171,7 +167,6 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
171 167
172 FreeStructs: 168 FreeStructs:
173 kfree(fcall); 169 kfree(fcall);
174 kfree(mi);
175 return ret; 170 return ret;
176} 171}
177 172
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index e13577da9130..6852f0eb96ed 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -32,6 +32,7 @@
32#include <linux/string.h> 32#include <linux/string.h>
33#include <linux/smp_lock.h> 33#include <linux/smp_lock.h>
34#include <linux/inet.h> 34#include <linux/inet.h>
35#include <linux/version.h>
35#include <linux/list.h> 36#include <linux/list.h>
36#include <asm/uaccess.h> 37#include <asm/uaccess.h>
37#include <linux/idr.h> 38#include <linux/idr.h>
@@ -117,9 +118,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
117 118
118 result = v9fs_t_open(v9ses, newfid, open_mode, &fcall); 119 result = v9fs_t_open(v9ses, newfid, open_mode, &fcall);
119 if (result < 0) { 120 if (result < 0) {
120 dprintk(DEBUG_ERROR, 121 PRINT_FCALL_ERROR("open failed", fcall);
121 "open failed, open_mode 0x%x: %s\n", open_mode,
122 FCALL_ERROR(fcall));
123 kfree(fcall); 122 kfree(fcall);
124 return result; 123 return result;
125 } 124 }
@@ -256,7 +255,6 @@ v9fs_file_write(struct file *filp, const char __user * data,
256 int result = -EIO; 255 int result = -EIO;
257 int rsize = 0; 256 int rsize = 0;
258 int total = 0; 257 int total = 0;
259 char *buf;
260 258
261 dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, 259 dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count,
262 (int)*offset); 260 (int)*offset);
@@ -264,28 +262,14 @@ v9fs_file_write(struct file *filp, const char __user * data,
264 if (v9fid->iounit != 0 && rsize > v9fid->iounit) 262 if (v9fid->iounit != 0 && rsize > v9fid->iounit)
265 rsize = v9fid->iounit; 263 rsize = v9fid->iounit;
266 264
267 buf = kmalloc(v9ses->maxdata - V9FS_IOHDRSZ, GFP_KERNEL);
268 if (!buf)
269 return -ENOMEM;
270
271 do { 265 do {
272 if (count < rsize) 266 if (count < rsize)
273 rsize = count; 267 rsize = count;
274 268
275 result = copy_from_user(buf, data, rsize); 269 result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall);
276 if (result) {
277 dprintk(DEBUG_ERROR, "Problem copying from user\n");
278 kfree(buf);
279 return -EFAULT;
280 }
281
282 dump_data(buf, rsize);
283 result = v9fs_t_write(v9ses, fid, *offset, rsize, buf, &fcall);
284 if (result < 0) { 270 if (result < 0) {
285 eprintk(KERN_ERR, "error while writing: %s(%d)\n", 271 PRINT_FCALL_ERROR("error while writing", fcall);
286 FCALL_ERROR(fcall), result);
287 kfree(fcall); 272 kfree(fcall);
288 kfree(buf);
289 return result; 273 return result;
290 } else 274 } else
291 *offset += result; 275 *offset += result;
@@ -305,7 +289,6 @@ v9fs_file_write(struct file *filp, const char __user * data,
305 total += result; 289 total += result;
306 } while (count); 290 } while (count);
307 291
308 kfree(buf);
309 return total; 292 return total;
310} 293}
311 294
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index f11edde6432e..742bcd0dc4a7 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -40,7 +40,6 @@
40#include "v9fs.h" 40#include "v9fs.h"
41#include "9p.h" 41#include "9p.h"
42#include "v9fs_vfs.h" 42#include "v9fs_vfs.h"
43#include "conv.h"
44#include "fid.h" 43#include "fid.h"
45 44
46static struct inode_operations v9fs_dir_inode_operations; 45static struct inode_operations v9fs_dir_inode_operations;
@@ -127,100 +126,32 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
127} 126}
128 127
129/** 128/**
130 * v9fs_blank_mistat - helper function to setup a 9P stat structure 129 * v9fs_blank_wstat - helper function to setup a 9P stat structure
131 * @v9ses: 9P session info (for determining extended mode) 130 * @v9ses: 9P session info (for determining extended mode)
132 * @mistat: structure to initialize 131 * @wstat: structure to initialize
133 * 132 *
134 */ 133 */
135 134
136static void 135static void
137v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat) 136v9fs_blank_wstat(struct v9fs_wstat *wstat)
138{ 137{
139 mistat->type = ~0; 138 wstat->type = ~0;
140 mistat->dev = ~0; 139 wstat->dev = ~0;
141 mistat->qid.type = ~0; 140 wstat->qid.type = ~0;
142 mistat->qid.version = ~0; 141 wstat->qid.version = ~0;
143 *((long long *)&mistat->qid.path) = ~0; 142 *((long long *)&wstat->qid.path) = ~0;
144 mistat->mode = ~0; 143 wstat->mode = ~0;
145 mistat->atime = ~0; 144 wstat->atime = ~0;
146 mistat->mtime = ~0; 145 wstat->mtime = ~0;
147 mistat->length = ~0; 146 wstat->length = ~0;
148 mistat->name = mistat->data; 147 wstat->name = NULL;
149 mistat->uid = mistat->data; 148 wstat->uid = NULL;
150 mistat->gid = mistat->data; 149 wstat->gid = NULL;
151 mistat->muid = mistat->data; 150 wstat->muid = NULL;
152 if (v9ses->extended) { 151 wstat->n_uid = ~0;
153 mistat->n_uid = ~0; 152 wstat->n_gid = ~0;
154 mistat->n_gid = ~0; 153 wstat->n_muid = ~0;
155 mistat->n_muid = ~0; 154 wstat->extension = NULL;
156 mistat->extension = mistat->data;
157 }
158 *mistat->data = 0;
159}
160
161/**
162 * v9fs_mistat2unix - convert mistat to unix stat
163 * @mistat: Plan 9 metadata (mistat) structure
164 * @buf: unix metadata (stat) structure to populate
165 * @sb: superblock
166 *
167 */
168
169static void
170v9fs_mistat2unix(struct v9fs_stat *mistat, struct stat *buf,
171 struct super_block *sb)
172{
173 struct v9fs_session_info *v9ses = sb ? sb->s_fs_info : NULL;
174
175 buf->st_nlink = 1;
176
177 buf->st_atime = mistat->atime;
178 buf->st_mtime = mistat->mtime;
179 buf->st_ctime = mistat->mtime;
180
181 buf->st_uid = (unsigned short)-1;
182 buf->st_gid = (unsigned short)-1;
183
184 if (v9ses && v9ses->extended) {
185 /* TODO: string to uid mapping via user-space daemon */
186 if (mistat->n_uid != -1)
187 sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid);
188
189 if (mistat->n_gid != -1)
190 sscanf(mistat->gid, "%x", (unsigned int *)&buf->st_gid);
191 }
192
193 if (buf->st_uid == (unsigned short)-1)
194 buf->st_uid = v9ses->uid;
195 if (buf->st_gid == (unsigned short)-1)
196 buf->st_gid = v9ses->gid;
197
198 buf->st_mode = p9mode2unixmode(v9ses, mistat->mode);
199 if ((S_ISBLK(buf->st_mode)) || (S_ISCHR(buf->st_mode))) {
200 char type = 0;
201 int major = -1;
202 int minor = -1;
203 sscanf(mistat->extension, "%c %u %u", &type, &major, &minor);
204 switch (type) {
205 case 'c':
206 buf->st_mode &= ~S_IFBLK;
207 buf->st_mode |= S_IFCHR;
208 break;
209 case 'b':
210 break;
211 default:
212 dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n",
213 type, mistat->extension);
214 };
215 buf->st_rdev = MKDEV(major, minor);
216 } else
217 buf->st_rdev = 0;
218
219 buf->st_size = mistat->length;
220
221 buf->st_blksize = sb->s_blocksize;
222 buf->st_blocks =
223 (buf->st_size + buf->st_blksize - 1) >> sb->s_blocksize_bits;
224} 155}
225 156
226/** 157/**
@@ -312,7 +243,6 @@ v9fs_create(struct inode *dir,
312 struct inode *file_inode = NULL; 243 struct inode *file_inode = NULL;
313 struct v9fs_fcall *fcall = NULL; 244 struct v9fs_fcall *fcall = NULL;
314 struct v9fs_qid qid; 245 struct v9fs_qid qid;
315 struct stat newstat;
316 int dirfidnum = -1; 246 int dirfidnum = -1;
317 long newfid = -1; 247 long newfid = -1;
318 int result = 0; 248 int result = 0;
@@ -350,7 +280,7 @@ v9fs_create(struct inode *dir,
350 280
351 result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall); 281 result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall);
352 if (result < 0) { 282 if (result < 0) {
353 dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); 283 PRINT_FCALL_ERROR("clone error", fcall);
354 v9fs_put_idpool(newfid, &v9ses->fidpool); 284 v9fs_put_idpool(newfid, &v9ses->fidpool);
355 newfid = -1; 285 newfid = -1;
356 goto CleanUpFid; 286 goto CleanUpFid;
@@ -362,9 +292,7 @@ v9fs_create(struct inode *dir,
362 result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, 292 result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name,
363 perm, open_mode, &fcall); 293 perm, open_mode, &fcall);
364 if (result < 0) { 294 if (result < 0) {
365 dprintk(DEBUG_ERROR, "create fails: %s(%d)\n", 295 PRINT_FCALL_ERROR("create fails", fcall);
366 FCALL_ERROR(fcall), result);
367
368 goto CleanUpFid; 296 goto CleanUpFid;
369 } 297 }
370 298
@@ -400,7 +328,7 @@ v9fs_create(struct inode *dir,
400 result = v9fs_t_walk(v9ses, dirfidnum, wfidno, 328 result = v9fs_t_walk(v9ses, dirfidnum, wfidno,
401 (char *) file_dentry->d_name.name, &fcall); 329 (char *) file_dentry->d_name.name, &fcall);
402 if (result < 0) { 330 if (result < 0) {
403 dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); 331 PRINT_FCALL_ERROR("clone error", fcall);
404 v9fs_put_idpool(wfidno, &v9ses->fidpool); 332 v9fs_put_idpool(wfidno, &v9ses->fidpool);
405 wfidno = -1; 333 wfidno = -1;
406 goto CleanUpFid; 334 goto CleanUpFid;
@@ -421,21 +349,21 @@ v9fs_create(struct inode *dir,
421 349
422 result = v9fs_t_stat(v9ses, wfidno, &fcall); 350 result = v9fs_t_stat(v9ses, wfidno, &fcall);
423 if (result < 0) { 351 if (result < 0) {
424 dprintk(DEBUG_ERROR, "stat error: %s(%d)\n", FCALL_ERROR(fcall), 352 PRINT_FCALL_ERROR("stat error", fcall);
425 result);
426 goto CleanUpFid; 353 goto CleanUpFid;
427 } 354 }
428 355
429 v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb);
430 356
431 file_inode = v9fs_get_inode(sb, newstat.st_mode); 357 file_inode = v9fs_get_inode(sb,
358 p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode));
359
432 if ((!file_inode) || IS_ERR(file_inode)) { 360 if ((!file_inode) || IS_ERR(file_inode)) {
433 dprintk(DEBUG_ERROR, "create inode failed\n"); 361 dprintk(DEBUG_ERROR, "create inode failed\n");
434 result = -EBADF; 362 result = -EBADF;
435 goto CleanUpFid; 363 goto CleanUpFid;
436 } 364 }
437 365
438 v9fs_mistat2inode(fcall->params.rstat.stat, file_inode, sb); 366 v9fs_stat2inode(&fcall->params.rstat.stat, file_inode, sb);
439 kfree(fcall); 367 kfree(fcall);
440 fcall = NULL; 368 fcall = NULL;
441 file_dentry->d_op = &v9fs_dentry_operations; 369 file_dentry->d_op = &v9fs_dentry_operations;
@@ -500,10 +428,9 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
500 } 428 }
501 429
502 result = v9fs_t_remove(v9ses, fid, &fcall); 430 result = v9fs_t_remove(v9ses, fid, &fcall);
503 if (result < 0) 431 if (result < 0) {
504 dprintk(DEBUG_ERROR, "remove of file fails: %s(%d)\n", 432 PRINT_FCALL_ERROR("remove fails", fcall);
505 FCALL_ERROR(fcall), result); 433 } else {
506 else {
507 v9fs_put_idpool(fid, &v9ses->fidpool); 434 v9fs_put_idpool(fid, &v9ses->fidpool);
508 v9fs_fid_destroy(v9fid); 435 v9fs_fid_destroy(v9fid);
509 } 436 }
@@ -558,7 +485,6 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
558 struct v9fs_fid *fid; 485 struct v9fs_fid *fid;
559 struct inode *inode; 486 struct inode *inode;
560 struct v9fs_fcall *fcall = NULL; 487 struct v9fs_fcall *fcall = NULL;
561 struct stat newstat;
562 int dirfidnum = -1; 488 int dirfidnum = -1;
563 int newfid = -1; 489 int newfid = -1;
564 int result = 0; 490 int result = 0;
@@ -611,8 +537,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
611 goto FreeFcall; 537 goto FreeFcall;
612 } 538 }
613 539
614 v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb); 540 inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses,
615 inode = v9fs_get_inode(sb, newstat.st_mode); 541 fcall->params.rstat.stat.mode));
616 542
617 if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { 543 if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) {
618 eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", 544 eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n",
@@ -622,7 +548,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
622 goto FreeFcall; 548 goto FreeFcall;
623 } 549 }
624 550
625 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid); 551 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid);
626 552
627 fid = v9fs_fid_create(dentry, v9ses, newfid, 0); 553 fid = v9fs_fid_create(dentry, v9ses, newfid, 0);
628 if (fid == NULL) { 554 if (fid == NULL) {
@@ -631,10 +557,10 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
631 goto FreeFcall; 557 goto FreeFcall;
632 } 558 }
633 559
634 fid->qid = fcall->params.rstat.stat->qid; 560 fid->qid = fcall->params.rstat.stat.qid;
635 561
636 dentry->d_op = &v9fs_dentry_operations; 562 dentry->d_op = &v9fs_dentry_operations;
637 v9fs_mistat2inode(fcall->params.rstat.stat, inode, inode->i_sb); 563 v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb);
638 564
639 d_add(dentry, inode); 565 d_add(dentry, inode);
640 kfree(fcall); 566 kfree(fcall);
@@ -690,7 +616,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
690 v9fs_fid_lookup(old_dentry->d_parent); 616 v9fs_fid_lookup(old_dentry->d_parent);
691 struct v9fs_fid *newdirfid = 617 struct v9fs_fid *newdirfid =
692 v9fs_fid_lookup(new_dentry->d_parent); 618 v9fs_fid_lookup(new_dentry->d_parent);
693 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); 619 struct v9fs_wstat wstat;
694 struct v9fs_fcall *fcall = NULL; 620 struct v9fs_fcall *fcall = NULL;
695 int fid = -1; 621 int fid = -1;
696 int olddirfidnum = -1; 622 int olddirfidnum = -1;
@@ -699,9 +625,6 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
699 625
700 dprintk(DEBUG_VFS, "\n"); 626 dprintk(DEBUG_VFS, "\n");
701 627
702 if (!mistat)
703 return -ENOMEM;
704
705 if ((!oldfid) || (!olddirfid) || (!newdirfid)) { 628 if ((!oldfid) || (!olddirfid) || (!newdirfid)) {
706 dprintk(DEBUG_ERROR, "problem with arguments\n"); 629 dprintk(DEBUG_ERROR, "problem with arguments\n");
707 return -EBADF; 630 return -EBADF;
@@ -725,26 +648,15 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
725 goto FreeFcallnBail; 648 goto FreeFcallnBail;
726 } 649 }
727 650
728 v9fs_blank_mistat(v9ses, mistat); 651 v9fs_blank_wstat(&wstat);
729 652 wstat.muid = v9ses->name;
730 strcpy(mistat->data + 1, v9ses->name); 653 wstat.name = (char *) new_dentry->d_name.name;
731 mistat->name = mistat->data + 1 + strlen(v9ses->name);
732
733 if (new_dentry->d_name.len >
734 (v9ses->maxdata - strlen(v9ses->name) - sizeof(struct v9fs_stat))) {
735 dprintk(DEBUG_ERROR, "new name too long\n");
736 goto FreeFcallnBail;
737 }
738 654
739 strcpy(mistat->name, new_dentry->d_name.name); 655 retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall);
740 retval = v9fs_t_wstat(v9ses, fid, mistat, &fcall);
741 656
742 FreeFcallnBail: 657 FreeFcallnBail:
743 kfree(mistat);
744
745 if (retval < 0) 658 if (retval < 0)
746 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", 659 PRINT_FCALL_ERROR("wstat error", fcall);
747 FCALL_ERROR(fcall));
748 660
749 kfree(fcall); 661 kfree(fcall);
750 return retval; 662 return retval;
@@ -779,7 +691,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
779 if (err < 0) 691 if (err < 0)
780 dprintk(DEBUG_ERROR, "stat error\n"); 692 dprintk(DEBUG_ERROR, "stat error\n");
781 else { 693 else {
782 v9fs_mistat2inode(fcall->params.rstat.stat, dentry->d_inode, 694 v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode,
783 dentry->d_inode->i_sb); 695 dentry->d_inode->i_sb);
784 generic_fillattr(dentry->d_inode, stat); 696 generic_fillattr(dentry->d_inode, stat);
785 } 697 }
@@ -800,57 +712,44 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
800 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); 712 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
801 struct v9fs_fid *fid = v9fs_fid_lookup(dentry); 713 struct v9fs_fid *fid = v9fs_fid_lookup(dentry);
802 struct v9fs_fcall *fcall = NULL; 714 struct v9fs_fcall *fcall = NULL;
803 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); 715 struct v9fs_wstat wstat;
804 int res = -EPERM; 716 int res = -EPERM;
805 717
806 dprintk(DEBUG_VFS, "\n"); 718 dprintk(DEBUG_VFS, "\n");
807 719
808 if (!mistat)
809 return -ENOMEM;
810
811 if (!fid) { 720 if (!fid) {
812 dprintk(DEBUG_ERROR, 721 dprintk(DEBUG_ERROR,
813 "Couldn't find fid associated with dentry\n"); 722 "Couldn't find fid associated with dentry\n");
814 return -EBADF; 723 return -EBADF;
815 } 724 }
816 725
817 v9fs_blank_mistat(v9ses, mistat); 726 v9fs_blank_wstat(&wstat);
818 if (iattr->ia_valid & ATTR_MODE) 727 if (iattr->ia_valid & ATTR_MODE)
819 mistat->mode = unixmode2p9mode(v9ses, iattr->ia_mode); 728 wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode);
820 729
821 if (iattr->ia_valid & ATTR_MTIME) 730 if (iattr->ia_valid & ATTR_MTIME)
822 mistat->mtime = iattr->ia_mtime.tv_sec; 731 wstat.mtime = iattr->ia_mtime.tv_sec;
823 732
824 if (iattr->ia_valid & ATTR_ATIME) 733 if (iattr->ia_valid & ATTR_ATIME)
825 mistat->atime = iattr->ia_atime.tv_sec; 734 wstat.atime = iattr->ia_atime.tv_sec;
826 735
827 if (iattr->ia_valid & ATTR_SIZE) 736 if (iattr->ia_valid & ATTR_SIZE)
828 mistat->length = iattr->ia_size; 737 wstat.length = iattr->ia_size;
829 738
830 if (v9ses->extended) { 739 if (v9ses->extended) {
831 char *ptr = mistat->data+1; 740 if (iattr->ia_valid & ATTR_UID)
741 wstat.n_uid = iattr->ia_uid;
832 742
833 if (iattr->ia_valid & ATTR_UID) { 743 if (iattr->ia_valid & ATTR_GID)
834 mistat->uid = ptr; 744 wstat.n_gid = iattr->ia_gid;
835 ptr += 1+sprintf(ptr, "%08x", iattr->ia_uid);
836 mistat->n_uid = iattr->ia_uid;
837 }
838
839 if (iattr->ia_valid & ATTR_GID) {
840 mistat->gid = ptr;
841 ptr += 1+sprintf(ptr, "%08x", iattr->ia_gid);
842 mistat->n_gid = iattr->ia_gid;
843 }
844 } 745 }
845 746
846 res = v9fs_t_wstat(v9ses, fid->fid, mistat, &fcall); 747 res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall);
847 748
848 if (res < 0) 749 if (res < 0)
849 dprintk(DEBUG_ERROR, "wstat error: %s\n", FCALL_ERROR(fcall)); 750 PRINT_FCALL_ERROR("wstat error", fcall);
850 751
851 kfree(mistat);
852 kfree(fcall); 752 kfree(fcall);
853
854 if (res >= 0) 753 if (res >= 0)
855 res = inode_setattr(dentry->d_inode, iattr); 754 res = inode_setattr(dentry->d_inode, iattr);
856 755
@@ -858,51 +757,42 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
858} 757}
859 758
860/** 759/**
861 * v9fs_mistat2inode - populate an inode structure with mistat info 760 * v9fs_stat2inode - populate an inode structure with mistat info
862 * @mistat: Plan 9 metadata (mistat) structure 761 * @stat: Plan 9 metadata (mistat) structure
863 * @inode: inode to populate 762 * @inode: inode to populate
864 * @sb: superblock of filesystem 763 * @sb: superblock of filesystem
865 * 764 *
866 */ 765 */
867 766
868void 767void
869v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode, 768v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
870 struct super_block *sb) 769 struct super_block *sb)
871{ 770{
771 char ext[32];
872 struct v9fs_session_info *v9ses = sb->s_fs_info; 772 struct v9fs_session_info *v9ses = sb->s_fs_info;
873 773
874 inode->i_nlink = 1; 774 inode->i_nlink = 1;
875 775
876 inode->i_atime.tv_sec = mistat->atime; 776 inode->i_atime.tv_sec = stat->atime;
877 inode->i_mtime.tv_sec = mistat->mtime; 777 inode->i_mtime.tv_sec = stat->mtime;
878 inode->i_ctime.tv_sec = mistat->mtime; 778 inode->i_ctime.tv_sec = stat->mtime;
879 779
880 inode->i_uid = -1; 780 inode->i_uid = v9ses->uid;
881 inode->i_gid = -1; 781 inode->i_gid = v9ses->gid;
882 782
883 if (v9ses->extended) { 783 if (v9ses->extended) {
884 /* TODO: string to uid mapping via user-space daemon */ 784 inode->i_uid = stat->n_uid;
885 inode->i_uid = mistat->n_uid; 785 inode->i_gid = stat->n_gid;
886 inode->i_gid = mistat->n_gid;
887
888 if (mistat->n_uid == -1)
889 sscanf(mistat->uid, "%x", &inode->i_uid);
890
891 if (mistat->n_gid == -1)
892 sscanf(mistat->gid, "%x", &inode->i_gid);
893 } 786 }
894 787
895 if (inode->i_uid == -1) 788 inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
896 inode->i_uid = v9ses->uid;
897 if (inode->i_gid == -1)
898 inode->i_gid = v9ses->gid;
899
900 inode->i_mode = p9mode2unixmode(v9ses, mistat->mode);
901 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { 789 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
902 char type = 0; 790 char type = 0;
903 int major = -1; 791 int major = -1;
904 int minor = -1; 792 int minor = -1;
905 sscanf(mistat->extension, "%c %u %u", &type, &major, &minor); 793
794 v9fs_str_copy(ext, sizeof(ext), &stat->extension);
795 sscanf(ext, "%c %u %u", &type, &major, &minor);
906 switch (type) { 796 switch (type) {
907 case 'c': 797 case 'c':
908 inode->i_mode &= ~S_IFBLK; 798 inode->i_mode &= ~S_IFBLK;
@@ -911,14 +801,14 @@ v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode,
911 case 'b': 801 case 'b':
912 break; 802 break;
913 default: 803 default:
914 dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n", 804 dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n",
915 type, mistat->extension); 805 type, stat->extension.len, stat->extension.str);
916 }; 806 };
917 inode->i_rdev = MKDEV(major, minor); 807 inode->i_rdev = MKDEV(major, minor);
918 } else 808 } else
919 inode->i_rdev = 0; 809 inode->i_rdev = 0;
920 810
921 inode->i_size = mistat->length; 811 inode->i_size = stat->length;
922 812
923 inode->i_blksize = sb->s_blocksize; 813 inode->i_blksize = sb->s_blocksize;
924 inode->i_blocks = 814 inode->i_blocks =
@@ -946,72 +836,6 @@ ino_t v9fs_qid2ino(struct v9fs_qid *qid)
946} 836}
947 837
948/** 838/**
949 * v9fs_vfs_symlink - helper function to create symlinks
950 * @dir: directory inode containing symlink
951 * @dentry: dentry for symlink
952 * @symname: symlink data
953 *
954 * See 9P2000.u RFC for more information
955 *
956 */
957
958static int
959v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
960{
961 int retval = -EPERM;
962 struct v9fs_fid *newfid;
963 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
964 struct v9fs_fcall *fcall = NULL;
965 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
966 int err;
967
968 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
969 symname);
970
971 if (!mistat)
972 return -ENOMEM;
973
974 if (!v9ses->extended) {
975 dprintk(DEBUG_ERROR, "not extended\n");
976 goto FreeFcall;
977 }
978
979 /* issue a create */
980 retval = v9fs_create(dir, dentry, S_IFLNK, 0);
981 if (retval != 0)
982 goto FreeFcall;
983
984 newfid = v9fs_fid_lookup(dentry);
985
986 /* issue a twstat */
987 v9fs_blank_mistat(v9ses, mistat);
988 strcpy(mistat->data + 1, symname);
989 mistat->extension = mistat->data + 1;
990 retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
991 if (retval < 0) {
992 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
993 FCALL_ERROR(fcall));
994 goto FreeFcall;
995 }
996
997 kfree(fcall);
998
999 err = v9fs_t_clunk(v9ses, newfid->fid);
1000 if (err < 0) {
1001 dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err);
1002 goto FreeFcall;
1003 }
1004
1005 d_drop(dentry); /* FID - will this also clunk? */
1006
1007 FreeFcall:
1008 kfree(mistat);
1009 kfree(fcall);
1010
1011 return retval;
1012}
1013
1014/**
1015 * v9fs_readlink - read a symlink's location (internal version) 839 * v9fs_readlink - read a symlink's location (internal version)
1016 * @dentry: dentry for symlink 840 * @dentry: dentry for symlink
1017 * @buffer: buffer to load symlink location into 841 * @buffer: buffer to load symlink location into
@@ -1050,16 +874,17 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
1050 if (!fcall) 874 if (!fcall)
1051 return -EIO; 875 return -EIO;
1052 876
1053 if (!(fcall->params.rstat.stat->mode & V9FS_DMSYMLINK)) { 877 if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) {
1054 retval = -EINVAL; 878 retval = -EINVAL;
1055 goto FreeFcall; 879 goto FreeFcall;
1056 } 880 }
1057 881
1058 /* copy extension buffer into buffer */ 882 /* copy extension buffer into buffer */
1059 if (strlen(fcall->params.rstat.stat->extension) < buflen) 883 if (fcall->params.rstat.stat.extension.len < buflen)
1060 buflen = strlen(fcall->params.rstat.stat->extension); 884 buflen = fcall->params.rstat.stat.extension.len;
1061 885
1062 memcpy(buffer, fcall->params.rstat.stat->extension, buflen + 1); 886 memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
887 buffer[buflen-1] = 0;
1063 888
1064 retval = buflen; 889 retval = buflen;
1065 890
@@ -1149,82 +974,111 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void
1149 __putname(s); 974 __putname(s);
1150} 975}
1151 976
1152/** 977static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1153 * v9fs_vfs_link - create a hardlink 978 int mode, const char *extension)
1154 * @old_dentry: dentry for file to link to
1155 * @dir: inode destination for new link
1156 * @dentry: dentry for link
1157 *
1158 */
1159
1160/* XXX - lots of code dup'd from symlink and creates,
1161 * figure out a better reuse strategy
1162 */
1163
1164static int
1165v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1166 struct dentry *dentry)
1167{ 979{
1168 int retval = -EPERM; 980 int err, retval;
1169 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); 981 struct v9fs_session_info *v9ses;
1170 struct v9fs_fcall *fcall = NULL; 982 struct v9fs_fcall *fcall;
1171 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); 983 struct v9fs_fid *fid;
1172 struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); 984 struct v9fs_wstat wstat;
1173 struct v9fs_fid *newfid = NULL;
1174 char *symname = __getname();
1175 int err;
1176 985
1177 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, 986 v9ses = v9fs_inode2v9ses(dir);
1178 old_dentry->d_name.name); 987 retval = -EPERM;
988 fcall = NULL;
1179 989
1180 if (!v9ses->extended) { 990 if (!v9ses->extended) {
1181 dprintk(DEBUG_ERROR, "not extended\n"); 991 dprintk(DEBUG_ERROR, "not extended\n");
1182 goto FreeMem; 992 goto free_mem;
1183 } 993 }
1184 994
1185 /* get fid of old_dentry */
1186 sprintf(symname, "hardlink(%d)\n", oldfid->fid);
1187
1188 /* issue a create */ 995 /* issue a create */
1189 retval = v9fs_create(dir, dentry, V9FS_DMLINK, 0); 996 retval = v9fs_create(dir, dentry, mode, 0);
1190 if (retval != 0) 997 if (retval != 0)
1191 goto FreeMem; 998 goto free_mem;
1192 999
1193 newfid = v9fs_fid_lookup(dentry); 1000 fid = v9fs_fid_get_created(dentry);
1194 if (!newfid) { 1001 if (!fid) {
1195 dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); 1002 dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n");
1196 goto FreeMem; 1003 goto free_mem;
1197 } 1004 }
1198 1005
1199 /* issue a twstat */ 1006 /* issue a Twstat */
1200 v9fs_blank_mistat(v9ses, mistat); 1007 v9fs_blank_wstat(&wstat);
1201 strcpy(mistat->data + 1, symname); 1008 wstat.muid = v9ses->name;
1202 mistat->extension = mistat->data + 1; 1009 wstat.extension = (char *) extension;
1203 retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); 1010 retval = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall);
1204 if (retval < 0) { 1011 if (retval < 0) {
1205 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", 1012 PRINT_FCALL_ERROR("wstat error", fcall);
1206 FCALL_ERROR(fcall)); 1013 goto free_mem;
1207 goto FreeMem;
1208 } 1014 }
1209 1015
1210 kfree(fcall); 1016 err = v9fs_t_clunk(v9ses, fid->fid);
1211
1212 err = v9fs_t_clunk(v9ses, newfid->fid);
1213
1214 if (err < 0) { 1017 if (err < 0) {
1215 dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err); 1018 dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
1216 goto FreeMem; 1019 goto free_mem;
1217 } 1020 }
1218 1021
1219 d_drop(dentry); /* FID - will this also clunk? */ 1022 d_drop(dentry); /* FID - will this also clunk? */
1220 1023
1024free_mem:
1221 kfree(fcall); 1025 kfree(fcall);
1222 fcall = NULL; 1026 return retval;
1027}
1028
1029/**
1030 * v9fs_vfs_symlink - helper function to create symlinks
1031 * @dir: directory inode containing symlink
1032 * @dentry: dentry for symlink
1033 * @symname: symlink data
1034 *
1035 * See 9P2000.u RFC for more information
1036 *
1037 */
1038
1039static int
1040v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
1041{
1042 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
1043 symname);
1044
1045 return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname);
1046}
1047
1048/**
1049 * v9fs_vfs_link - create a hardlink
1050 * @old_dentry: dentry for file to link to
1051 * @dir: inode destination for new link
1052 * @dentry: dentry for link
1053 *
1054 */
1055
1056/* XXX - lots of code dup'd from symlink and creates,
1057 * figure out a better reuse strategy
1058 */
1059
1060static int
1061v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1062 struct dentry *dentry)
1063{
1064 int retval;
1065 struct v9fs_fid *oldfid;
1066 char *name;
1067
1068 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
1069 old_dentry->d_name.name);
1070
1071 oldfid = v9fs_fid_lookup(old_dentry);
1072 if (!oldfid) {
1073 dprintk(DEBUG_ERROR, "can't find oldfid\n");
1074 return -EPERM;
1075 }
1076
1077 name = __getname();
1078 sprintf(name, "hardlink(%d)\n", oldfid->fid);
1079 retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
1080 __putname(name);
1223 1081
1224 FreeMem:
1225 kfree(mistat);
1226 kfree(fcall);
1227 __putname(symname);
1228 return retval; 1082 return retval;
1229} 1083}
1230 1084
@@ -1240,83 +1094,30 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1240static int 1094static int
1241v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) 1095v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
1242{ 1096{
1243 int retval = -EPERM; 1097 int retval;
1244 struct v9fs_fid *newfid; 1098 char *name;
1245 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
1246 struct v9fs_fcall *fcall = NULL;
1247 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
1248 char *symname = __getname();
1249 int err;
1250 1099
1251 dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, 1100 dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
1252 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); 1101 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
1253 1102
1254 if (!mistat) 1103 if (!new_valid_dev(rdev))
1255 return -ENOMEM; 1104 return -EINVAL;
1256
1257 if (!new_valid_dev(rdev)) {
1258 retval = -EINVAL;
1259 goto FreeMem;
1260 }
1261
1262 if (!v9ses->extended) {
1263 dprintk(DEBUG_ERROR, "not extended\n");
1264 goto FreeMem;
1265 }
1266
1267 /* issue a create */
1268 retval = v9fs_create(dir, dentry, mode, 0);
1269
1270 if (retval != 0)
1271 goto FreeMem;
1272
1273 newfid = v9fs_fid_lookup(dentry);
1274 if (!newfid) {
1275 dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n");
1276 retval = -EINVAL;
1277 goto FreeMem;
1278 }
1279 1105
1106 name = __getname();
1280 /* build extension */ 1107 /* build extension */
1281 if (S_ISBLK(mode)) 1108 if (S_ISBLK(mode))
1282 sprintf(symname, "b %u %u", MAJOR(rdev), MINOR(rdev)); 1109 sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
1283 else if (S_ISCHR(mode)) 1110 else if (S_ISCHR(mode))
1284 sprintf(symname, "c %u %u", MAJOR(rdev), MINOR(rdev)); 1111 sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
1285 else if (S_ISFIFO(mode)) 1112 else if (S_ISFIFO(mode))
1286 ; /* DO NOTHING */ 1113 *name = 0;
1287 else { 1114 else {
1288 retval = -EINVAL; 1115 __putname(name);
1289 goto FreeMem; 1116 return -EINVAL;
1290 } 1117 }
1291 1118
1292 if (!S_ISFIFO(mode)) { 1119 retval = v9fs_vfs_mkspecial(dir, dentry, mode, name);
1293 /* issue a twstat */ 1120 __putname(name);
1294 v9fs_blank_mistat(v9ses, mistat);
1295 strcpy(mistat->data + 1, symname);
1296 mistat->extension = mistat->data + 1;
1297 retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
1298 if (retval < 0) {
1299 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
1300 FCALL_ERROR(fcall));
1301 goto FreeMem;
1302 }
1303 }
1304
1305 /* need to update dcache so we show up */
1306 kfree(fcall);
1307
1308 err = v9fs_t_clunk(v9ses, newfid->fid);
1309 if (err < 0) {
1310 dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err);
1311 goto FreeMem;
1312 }
1313
1314 d_drop(dentry); /* FID - will this also clunk? */
1315
1316 FreeMem:
1317 kfree(mistat);
1318 kfree(fcall);
1319 __putname(symname);
1320 1121
1321 return retval; 1122 return retval;
1322} 1123}
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 83b6edd0988a..d4d71a9ca573 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -44,7 +44,6 @@
44#include "v9fs.h" 44#include "v9fs.h"
45#include "9p.h" 45#include "9p.h"
46#include "v9fs_vfs.h" 46#include "v9fs_vfs.h"
47#include "conv.h"
48#include "fid.h" 47#include "fid.h"
49 48
50static void v9fs_clear_inode(struct inode *); 49static void v9fs_clear_inode(struct inode *);
@@ -123,10 +122,11 @@ static struct super_block *v9fs_get_sb(struct file_system_type
123 122
124 dprintk(DEBUG_VFS, " \n"); 123 dprintk(DEBUG_VFS, " \n");
125 124
126 v9ses = kcalloc(1, sizeof(struct v9fs_session_info), GFP_KERNEL); 125 v9ses = kmalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
127 if (!v9ses) 126 if (!v9ses)
128 return ERR_PTR(-ENOMEM); 127 return ERR_PTR(-ENOMEM);
129 128
129 memset(v9ses, 0, sizeof(struct v9fs_session_info));
130 if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { 130 if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
131 dprintk(DEBUG_ERROR, "problem initiating session\n"); 131 dprintk(DEBUG_ERROR, "problem initiating session\n");
132 kfree(v9ses); 132 kfree(v9ses);
@@ -168,10 +168,10 @@ static struct super_block *v9fs_get_sb(struct file_system_type
168 goto put_back_sb; 168 goto put_back_sb;
169 } 169 }
170 170
171 root_fid->qid = fcall->params.rstat.stat->qid; 171 root_fid->qid = fcall->params.rstat.stat.qid;
172 root->d_inode->i_ino = 172 root->d_inode->i_ino =
173 v9fs_qid2ino(&fcall->params.rstat.stat->qid); 173 v9fs_qid2ino(&fcall->params.rstat.stat.qid);
174 v9fs_mistat2inode(fcall->params.rstat.stat, root->d_inode, sb); 174 v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb);
175 } 175 }
176 176
177 kfree(fcall); 177 kfree(fcall);