[PATCH] v9fs: zero copy implementation
[linux-block.git] / fs / 9p / conv.c
CommitLineData
b8cf945b
EVH
1/*
2 * linux/fs/9p/conv.c
3 *
4 * 9P protocol conversion functions
5 *
d06a8fb1 6 * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
b8cf945b
EVH
7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to:
22 * Free Software Foundation
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02111-1301 USA
25 *
26 */
27
28#include <linux/config.h>
29#include <linux/module.h>
30#include <linux/errno.h>
31#include <linux/fs.h>
32#include <linux/idr.h>
531b1094 33#include <asm/uaccess.h>
b8cf945b
EVH
34#include "debug.h"
35#include "v9fs.h"
36#include "9p.h"
37#include "conv.h"
38
39/*
40 * Buffer to help with string parsing
41 */
42struct cbuf {
43 unsigned char *sp;
44 unsigned char *p;
45 unsigned char *ep;
46};
47
531b1094
LI
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
b8cf945b
EVH
79static inline void buf_init(struct cbuf *buf, void *data, int datalen)
80{
81 buf->sp = buf->p = data;
82 buf->ep = data + datalen;
83}
84
85static inline int buf_check_overflow(struct cbuf *buf)
86{
87 return buf->p > buf->ep;
88}
89
d06a8fb1 90static inline int buf_check_size(struct cbuf *buf, int len)
b8cf945b 91{
531b1094
LI
92 if (buf->p + len > buf->ep && buf->p < buf->ep) {
93 eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
94 len, (int)(buf->ep - buf->p));
95 dump_stack();
96 buf->p = buf->ep + 1;
97 return 0;
b8cf945b 98 }
d06a8fb1
LI
99
100 return 1;
b8cf945b
EVH
101}
102
103static inline void *buf_alloc(struct cbuf *buf, int len)
104{
105 void *ret = NULL;
106
d06a8fb1
LI
107 if (buf_check_size(buf, len)) {
108 ret = buf->p;
109 buf->p += len;
110 }
b8cf945b
EVH
111
112 return ret;
113}
114
115static inline void buf_put_int8(struct cbuf *buf, u8 val)
116{
d06a8fb1
LI
117 if (buf_check_size(buf, 1)) {
118 buf->p[0] = val;
119 buf->p++;
120 }
b8cf945b
EVH
121}
122
123static inline void buf_put_int16(struct cbuf *buf, u16 val)
124{
d06a8fb1
LI
125 if (buf_check_size(buf, 2)) {
126 *(__le16 *) buf->p = cpu_to_le16(val);
127 buf->p += 2;
128 }
b8cf945b
EVH
129}
130
131static inline void buf_put_int32(struct cbuf *buf, u32 val)
132{
d06a8fb1
LI
133 if (buf_check_size(buf, 4)) {
134 *(__le32 *)buf->p = cpu_to_le32(val);
135 buf->p += 4;
136 }
b8cf945b
EVH
137}
138
139static inline void buf_put_int64(struct cbuf *buf, u64 val)
140{
d06a8fb1
LI
141 if (buf_check_size(buf, 8)) {
142 *(__le64 *)buf->p = cpu_to_le64(val);
143 buf->p += 8;
144 }
b8cf945b
EVH
145}
146
147static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
148{
d06a8fb1
LI
149 if (buf_check_size(buf, slen + 2)) {
150 buf_put_int16(buf, slen);
151 memcpy(buf->p, s, slen);
152 buf->p += slen;
153 }
b8cf945b
EVH
154}
155
156static inline void buf_put_string(struct cbuf *buf, const char *s)
157{
158 buf_put_stringn(buf, s, strlen(s));
159}
160
b8cf945b
EVH
161static inline u8 buf_get_int8(struct cbuf *buf)
162{
163 u8 ret = 0;
164
d06a8fb1
LI
165 if (buf_check_size(buf, 1)) {
166 ret = buf->p[0];
167 buf->p++;
168 }
b8cf945b
EVH
169
170 return ret;
171}
172
173static inline u16 buf_get_int16(struct cbuf *buf)
174{
175 u16 ret = 0;
176
d06a8fb1
LI
177 if (buf_check_size(buf, 2)) {
178 ret = le16_to_cpu(*(__le16 *)buf->p);
179 buf->p += 2;
180 }
b8cf945b
EVH
181
182 return ret;
183}
184
185static inline u32 buf_get_int32(struct cbuf *buf)
186{
187 u32 ret = 0;
188
d06a8fb1
LI
189 if (buf_check_size(buf, 4)) {
190 ret = le32_to_cpu(*(__le32 *)buf->p);
191 buf->p += 4;
192 }
b8cf945b
EVH
193
194 return ret;
195}
196
197static inline u64 buf_get_int64(struct cbuf *buf)
198{
199 u64 ret = 0;
200
d06a8fb1
LI
201 if (buf_check_size(buf, 8)) {
202 ret = le64_to_cpu(*(__le64 *)buf->p);
203 buf->p += 8;
204 }
b8cf945b
EVH
205
206 return ret;
207}
208
531b1094 209static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
b8cf945b 210{
531b1094
LI
211 vstr->len = buf_get_int16(buf);
212 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
213 vstr->str = buf->p;
214 buf->p += vstr->len;
215 } else {
216 vstr->len = 0;
217 vstr->str = NULL;
d06a8fb1 218 }
b8cf945b
EVH
219}
220
531b1094 221static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
b8cf945b 222{
531b1094
LI
223 qid->type = buf_get_int8(bufp);
224 qid->version = buf_get_int32(bufp);
225 qid->path = buf_get_int64(bufp);
b8cf945b
EVH
226}
227
228/**
531b1094 229 * v9fs_size_wstat - calculate the size of a variable length stat struct
b8cf945b 230 * @stat: metadata (stat) structure
3cf6429a 231 * @extended: non-zero if 9P2000.u
b8cf945b
EVH
232 *
233 */
234
531b1094 235static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
b8cf945b
EVH
236{
237 int size = 0;
238
531b1094 239 if (wstat == NULL) {
b8cf945b
EVH
240 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
241 return 0;
242 }
243
244 size = /* 2 + *//* size[2] */
245 2 + /* type[2] */
246 4 + /* dev[4] */
247 1 + /* qid.type[1] */
248 4 + /* qid.vers[4] */
249 8 + /* qid.path[8] */
250 4 + /* mode[4] */
251 4 + /* atime[4] */
252 4 + /* mtime[4] */
253 8 + /* length[8] */
254 8; /* minimum sum of string lengths */
255
531b1094
LI
256 if (wstat->name)
257 size += strlen(wstat->name);
258 if (wstat->uid)
259 size += strlen(wstat->uid);
260 if (wstat->gid)
261 size += strlen(wstat->gid);
262 if (wstat->muid)
263 size += strlen(wstat->muid);
b8cf945b 264
3cf6429a 265 if (extended) {
b8cf945b
EVH
266 size += 4 + /* n_uid[4] */
267 4 + /* n_gid[4] */
268 4 + /* n_muid[4] */
269 2; /* string length of extension[4] */
531b1094
LI
270 if (wstat->extension)
271 size += strlen(wstat->extension);
b8cf945b
EVH
272 }
273
274 return size;
275}
276
277/**
531b1094 278 * buf_get_stat - safely decode a recieved metadata (stat) structure
b8cf945b
EVH
279 * @bufp: buffer to deserialize
280 * @stat: metadata (stat) structure
3cf6429a 281 * @extended: non-zero if 9P2000.u
b8cf945b
EVH
282 *
283 */
284
531b1094
LI
285static inline void
286buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
b8cf945b 287{
b8cf945b
EVH
288 stat->size = buf_get_int16(bufp);
289 stat->type = buf_get_int16(bufp);
290 stat->dev = buf_get_int32(bufp);
291 stat->qid.type = buf_get_int8(bufp);
292 stat->qid.version = buf_get_int32(bufp);
293 stat->qid.path = buf_get_int64(bufp);
294 stat->mode = buf_get_int32(bufp);
295 stat->atime = buf_get_int32(bufp);
296 stat->mtime = buf_get_int32(bufp);
297 stat->length = buf_get_int64(bufp);
531b1094
LI
298 buf_get_str(bufp, &stat->name);
299 buf_get_str(bufp, &stat->uid);
300 buf_get_str(bufp, &stat->gid);
301 buf_get_str(bufp, &stat->muid);
b8cf945b 302
3cf6429a 303 if (extended) {
531b1094 304 buf_get_str(bufp, &stat->extension);
b8cf945b
EVH
305 stat->n_uid = buf_get_int32(bufp);
306 stat->n_gid = buf_get_int32(bufp);
307 stat->n_muid = buf_get_int32(bufp);
308 }
b8cf945b
EVH
309}
310
311/**
312 * v9fs_deserialize_stat - decode a received metadata structure
b8cf945b
EVH
313 * @buf: buffer to deserialize
314 * @buflen: length of received buffer
315 * @stat: metadata structure to decode into
3cf6429a 316 * @extended: non-zero if 9P2000.u
b8cf945b 317 *
531b1094 318 * Note: stat will point to the buf region.
b8cf945b
EVH
319 */
320
531b1094
LI
321int
322v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
323 int extended)
b8cf945b
EVH
324{
325 struct cbuf buffer;
326 struct cbuf *bufp = &buffer;
531b1094 327 unsigned char *p;
b8cf945b
EVH
328
329 buf_init(bufp, buf, buflen);
531b1094
LI
330 p = bufp->p;
331 buf_get_stat(bufp, stat, extended);
b8cf945b 332
531b1094 333 if (buf_check_overflow(bufp))
b8cf945b 334 return 0;
531b1094
LI
335 else
336 return bufp->p - p;
b8cf945b
EVH
337}
338
339/**
340 * deserialize_fcall - unmarshal a response
b8cf945b
EVH
341 * @buf: recieved buffer
342 * @buflen: length of received buffer
343 * @rcall: fcall structure to populate
344 * @rcalllen: length of fcall structure to populate
3cf6429a 345 * @extended: non-zero if 9P2000.u
b8cf945b
EVH
346 *
347 */
348
349int
3cf6429a 350v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
531b1094 351 int extended)
b8cf945b
EVH
352{
353
354 struct cbuf buffer;
355 struct cbuf *bufp = &buffer;
b8cf945b
EVH
356 int i = 0;
357
358 buf_init(bufp, buf, buflen);
b8cf945b 359
3cf6429a 360 rcall->size = buf_get_int32(bufp);
b8cf945b
EVH
361 rcall->id = buf_get_int8(bufp);
362 rcall->tag = buf_get_int16(bufp);
363
364 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
365 rcall->tag);
531b1094 366
b8cf945b
EVH
367 switch (rcall->id) {
368 default:
369 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
370 return -EPROTO;
371 case RVERSION:
372 rcall->params.rversion.msize = buf_get_int32(bufp);
531b1094 373 buf_get_str(bufp, &rcall->params.rversion.version);
b8cf945b
EVH
374 break;
375 case RFLUSH:
376 break;
377 case RATTACH:
378 rcall->params.rattach.qid.type = buf_get_int8(bufp);
379 rcall->params.rattach.qid.version = buf_get_int32(bufp);
380 rcall->params.rattach.qid.path = buf_get_int64(bufp);
381 break;
382 case RWALK:
383 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
531b1094
LI
384 if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
385 eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
386 V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
3cf6429a
LI
387 return -EPROTO;
388 }
389
531b1094
LI
390 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
391 buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
b8cf945b
EVH
392 break;
393 case ROPEN:
531b1094 394 buf_get_qid(bufp, &rcall->params.ropen.qid);
b8cf945b
EVH
395 rcall->params.ropen.iounit = buf_get_int32(bufp);
396 break;
397 case RCREATE:
531b1094 398 buf_get_qid(bufp, &rcall->params.rcreate.qid);
b8cf945b
EVH
399 rcall->params.rcreate.iounit = buf_get_int32(bufp);
400 break;
401 case RREAD:
402 rcall->params.rread.count = buf_get_int32(bufp);
531b1094
LI
403 rcall->params.rread.data = bufp->p;
404 buf_check_size(bufp, rcall->params.rread.count);
b8cf945b
EVH
405 break;
406 case RWRITE:
407 rcall->params.rwrite.count = buf_get_int32(bufp);
408 break;
409 case RCLUNK:
410 break;
411 case RREMOVE:
412 break;
413 case RSTAT:
414 buf_get_int16(bufp);
531b1094 415 buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
b8cf945b
EVH
416 break;
417 case RWSTAT:
418 break;
419 case RERROR:
531b1094 420 buf_get_str(bufp, &rcall->params.rerror.error);
3cf6429a 421 if (extended)
b8cf945b
EVH
422 rcall->params.rerror.errno = buf_get_int16(bufp);
423 break;
424 }
425
531b1094 426 if (buf_check_overflow(bufp)) {
3cf6429a 427 dprintk(DEBUG_ERROR, "buffer overflow\n");
b8cf945b 428 return -EIO;
3cf6429a 429 }
b8cf945b 430
531b1094
LI
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;
b8cf945b 853}