aboutsummaryrefslogtreecommitdiffstats
path: root/fs/9p/conv.c
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/conv.c
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/conv.c')
-rw-r--r--fs/9p/conv.c895
1 files changed, 518 insertions, 377 deletions
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}