[PATCH] v9fs: zero copy implementation
[linux-2.6.git] / fs / 9p / conv.c
1 /*
2  * linux/fs/9p/conv.c
3  *
4  * 9P protocol conversion functions
5  *
6  *  Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
7  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License 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>
33 #include <asm/uaccess.h>
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  */
42 struct cbuf {
43         unsigned char *sp;
44         unsigned char *p;
45         unsigned char *ep;
46 };
47
48 char *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
62 int 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
79 static 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
85 static inline int buf_check_overflow(struct cbuf *buf)
86 {
87         return buf->p > buf->ep;
88 }
89
90 static inline int buf_check_size(struct cbuf *buf, int len)
91 {
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;
98         }
99
100         return 1;
101 }
102
103 static inline void *buf_alloc(struct cbuf *buf, int len)
104 {
105         void *ret = NULL;
106
107         if (buf_check_size(buf, len)) {
108                 ret = buf->p;
109                 buf->p += len;
110         }
111
112         return ret;
113 }
114
115 static inline void buf_put_int8(struct cbuf *buf, u8 val)
116 {
117         if (buf_check_size(buf, 1)) {
118                 buf->p[0] = val;
119                 buf->p++;
120         }
121 }
122
123 static inline void buf_put_int16(struct cbuf *buf, u16 val)
124 {
125         if (buf_check_size(buf, 2)) {
126                 *(__le16 *) buf->p = cpu_to_le16(val);
127                 buf->p += 2;
128         }
129 }
130
131 static inline void buf_put_int32(struct cbuf *buf, u32 val)
132 {
133         if (buf_check_size(buf, 4)) {
134                 *(__le32 *)buf->p = cpu_to_le32(val);
135                 buf->p += 4;
136         }
137 }
138
139 static inline void buf_put_int64(struct cbuf *buf, u64 val)
140 {
141         if (buf_check_size(buf, 8)) {
142                 *(__le64 *)buf->p = cpu_to_le64(val);
143                 buf->p += 8;
144         }
145 }
146
147 static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
148 {
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         }
154 }
155
156 static inline void buf_put_string(struct cbuf *buf, const char *s)
157 {
158         buf_put_stringn(buf, s, strlen(s));
159 }
160
161 static inline u8 buf_get_int8(struct cbuf *buf)
162 {
163         u8 ret = 0;
164
165         if (buf_check_size(buf, 1)) {
166                 ret = buf->p[0];
167                 buf->p++;
168         }
169
170         return ret;
171 }
172
173 static inline u16 buf_get_int16(struct cbuf *buf)
174 {
175         u16 ret = 0;
176
177         if (buf_check_size(buf, 2)) {
178                 ret = le16_to_cpu(*(__le16 *)buf->p);
179                 buf->p += 2;
180         }
181
182         return ret;
183 }
184
185 static inline u32 buf_get_int32(struct cbuf *buf)
186 {
187         u32 ret = 0;
188
189         if (buf_check_size(buf, 4)) {
190                 ret = le32_to_cpu(*(__le32 *)buf->p);
191                 buf->p += 4;
192         }
193
194         return ret;
195 }
196
197 static inline u64 buf_get_int64(struct cbuf *buf)
198 {
199         u64 ret = 0;
200
201         if (buf_check_size(buf, 8)) {
202                 ret = le64_to_cpu(*(__le64 *)buf->p);
203                 buf->p += 8;
204         }
205
206         return ret;
207 }
208
209 static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
210 {
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;
218         }
219 }
220
221 static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
222 {
223         qid->type = buf_get_int8(bufp);
224         qid->version = buf_get_int32(bufp);
225         qid->path = buf_get_int64(bufp);
226 }
227
228 /**
229  * v9fs_size_wstat - calculate the size of a variable length stat struct
230  * @stat: metadata (stat) structure
231  * @extended: non-zero if 9P2000.u
232  *
233  */
234
235 static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
236 {
237         int size = 0;
238
239         if (wstat == NULL) {
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
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);
264
265         if (extended) {
266                 size += 4 +     /* n_uid[4] */
267                     4 +         /* n_gid[4] */
268                     4 +         /* n_muid[4] */
269                     2;          /* string length of extension[4] */
270                 if (wstat->extension)
271                         size += strlen(wstat->extension);
272         }
273
274         return size;
275 }
276
277 /**
278  * buf_get_stat - safely decode a recieved metadata (stat) structure
279  * @bufp: buffer to deserialize
280  * @stat: metadata (stat) structure
281  * @extended: non-zero if 9P2000.u
282  *
283  */
284
285 static inline void
286 buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
287 {
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);
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);
302
303         if (extended) {
304                 buf_get_str(bufp, &stat->extension);
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         }
309 }
310
311 /**
312  * v9fs_deserialize_stat - decode a received metadata structure
313  * @buf: buffer to deserialize
314  * @buflen: length of received buffer
315  * @stat: metadata structure to decode into
316  * @extended: non-zero if 9P2000.u
317  *
318  * Note: stat will point to the buf region.
319  */
320
321 int
322 v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
323                 int extended)
324 {
325         struct cbuf buffer;
326         struct cbuf *bufp = &buffer;
327         unsigned char *p;
328
329         buf_init(bufp, buf, buflen);
330         p = bufp->p;
331         buf_get_stat(bufp, stat, extended);
332
333         if (buf_check_overflow(bufp))
334                 return 0;
335         else
336                 return bufp->p - p;
337 }
338
339 /**
340  * deserialize_fcall - unmarshal a response
341  * @buf: recieved buffer
342  * @buflen: length of received buffer
343  * @rcall: fcall structure to populate
344  * @rcalllen: length of fcall structure to populate
345  * @extended: non-zero if 9P2000.u
346  *
347  */
348
349 int
350 v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
351                        int extended)
352 {
353
354         struct cbuf buffer;
355         struct cbuf *bufp = &buffer;
356         int i = 0;
357
358         buf_init(bufp, buf, buflen);
359
360         rcall->size = buf_get_int32(bufp);
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);
366
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);
373                 buf_get_str(bufp, &rcall->params.rversion.version);
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);
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);
387                         return -EPROTO;
388                 }
389
390                 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
391                         buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
392                 break;
393         case ROPEN:
394                 buf_get_qid(bufp, &rcall->params.ropen.qid);
395                 rcall->params.ropen.iounit = buf_get_int32(bufp);
396                 break;
397         case RCREATE:
398                 buf_get_qid(bufp, &rcall->params.rcreate.qid);
399                 rcall->params.rcreate.iounit = buf_get_int32(bufp);
400                 break;
401         case RREAD:
402                 rcall->params.rread.count = buf_get_int32(bufp);
403                 rcall->params.rread.data = bufp->p;
404                 buf_check_size(bufp, rcall->params.rread.count);
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);
415                 buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
416                 break;
417         case RWSTAT:
418                 break;
419         case RERROR:
420                 buf_get_str(bufp, &rcall->params.rerror.error);
421                 if (extended)
422                         rcall->params.rerror.errno = buf_get_int16(bufp);
423                 break;
424         }
425
426         if (buf_check_overflow(bufp)) {
427                 dprintk(DEBUG_ERROR, "buffer overflow\n");
428                 return -EIO;
429         }
430
431         return bufp->p - bufp->sp;
432 }
433
434 static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
435 {
436         *p = val;
437         buf_put_int8(bufp, val);
438 }
439
440 static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
441 {
442         *p = val;
443         buf_put_int16(bufp, val);
444 }
445
446 static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
447 {
448         *p = val;
449         buf_put_int32(bufp, val);
450 }
451
452 static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
453 {
454         *p = val;
455         buf_put_int64(bufp, val);
456 }
457
458 static inline void
459 v9fs_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
472 static inline int
473 v9fs_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
480 static void
481 v9fs_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
508 static struct v9fs_fcall *
509 v9fs_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
528 void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
529 {
530         *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
531 }
532
533 struct 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
556 struct 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
580 struct v9fs_fcall *
581 v9fs_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
602 struct 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
624 struct 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
661 struct 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
684 struct 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
709 struct 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
733 struct 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
763 struct 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
785 struct 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
807 struct 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
829 struct 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;
853 }