[PATCH] v9fs: handle kthread_create failure, minor bugfixes
[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 static inline void buf_init(struct cbuf *buf, void *data, int datalen)
49 {
50         buf->sp = buf->p = data;
51         buf->ep = data + datalen;
52 }
53
54 static inline int buf_check_overflow(struct cbuf *buf)
55 {
56         return buf->p > buf->ep;
57 }
58
59 static inline int buf_check_size(struct cbuf *buf, int len)
60 {
61         if (buf->p + len > buf->ep) {
62                 if (buf->p < buf->ep) {
63                         eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
64                                 len, (int)(buf->ep - buf->p));
65                         dump_stack();
66                         buf->p = buf->ep + 1;
67                 }
68
69                 return 0;
70         }
71
72         return 1;
73 }
74
75 static inline void *buf_alloc(struct cbuf *buf, int len)
76 {
77         void *ret = NULL;
78
79         if (buf_check_size(buf, len)) {
80                 ret = buf->p;
81                 buf->p += len;
82         }
83
84         return ret;
85 }
86
87 static inline void buf_put_int8(struct cbuf *buf, u8 val)
88 {
89         if (buf_check_size(buf, 1)) {
90                 buf->p[0] = val;
91                 buf->p++;
92         }
93 }
94
95 static inline void buf_put_int16(struct cbuf *buf, u16 val)
96 {
97         if (buf_check_size(buf, 2)) {
98                 *(__le16 *) buf->p = cpu_to_le16(val);
99                 buf->p += 2;
100         }
101 }
102
103 static inline void buf_put_int32(struct cbuf *buf, u32 val)
104 {
105         if (buf_check_size(buf, 4)) {
106                 *(__le32 *)buf->p = cpu_to_le32(val);
107                 buf->p += 4;
108         }
109 }
110
111 static inline void buf_put_int64(struct cbuf *buf, u64 val)
112 {
113         if (buf_check_size(buf, 8)) {
114                 *(__le64 *)buf->p = cpu_to_le64(val);
115                 buf->p += 8;
116         }
117 }
118
119 static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
120 {
121         if (buf_check_size(buf, slen + 2)) {
122                 buf_put_int16(buf, slen);
123                 memcpy(buf->p, s, slen);
124                 buf->p += slen;
125         }
126 }
127
128 static inline void buf_put_string(struct cbuf *buf, const char *s)
129 {
130         buf_put_stringn(buf, s, strlen(s));
131 }
132
133 static inline u8 buf_get_int8(struct cbuf *buf)
134 {
135         u8 ret = 0;
136
137         if (buf_check_size(buf, 1)) {
138                 ret = buf->p[0];
139                 buf->p++;
140         }
141
142         return ret;
143 }
144
145 static inline u16 buf_get_int16(struct cbuf *buf)
146 {
147         u16 ret = 0;
148
149         if (buf_check_size(buf, 2)) {
150                 ret = le16_to_cpu(*(__le16 *)buf->p);
151                 buf->p += 2;
152         }
153
154         return ret;
155 }
156
157 static inline u32 buf_get_int32(struct cbuf *buf)
158 {
159         u32 ret = 0;
160
161         if (buf_check_size(buf, 4)) {
162                 ret = le32_to_cpu(*(__le32 *)buf->p);
163                 buf->p += 4;
164         }
165
166         return ret;
167 }
168
169 static inline u64 buf_get_int64(struct cbuf *buf)
170 {
171         u64 ret = 0;
172
173         if (buf_check_size(buf, 8)) {
174                 ret = le64_to_cpu(*(__le64 *)buf->p);
175                 buf->p += 8;
176         }
177
178         return ret;
179 }
180
181 static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
182 {
183         vstr->len = buf_get_int16(buf);
184         if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
185                 vstr->str = buf->p;
186                 buf->p += vstr->len;
187         } else {
188                 vstr->len = 0;
189                 vstr->str = NULL;
190         }
191 }
192
193 static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
194 {
195         qid->type = buf_get_int8(bufp);
196         qid->version = buf_get_int32(bufp);
197         qid->path = buf_get_int64(bufp);
198 }
199
200 /**
201  * v9fs_size_wstat - calculate the size of a variable length stat struct
202  * @stat: metadata (stat) structure
203  * @extended: non-zero if 9P2000.u
204  *
205  */
206
207 static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
208 {
209         int size = 0;
210
211         if (wstat == NULL) {
212                 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
213                 return 0;
214         }
215
216         size =                  /* 2 + *//* size[2] */
217             2 +                 /* type[2] */
218             4 +                 /* dev[4] */
219             1 +                 /* qid.type[1] */
220             4 +                 /* qid.vers[4] */
221             8 +                 /* qid.path[8] */
222             4 +                 /* mode[4] */
223             4 +                 /* atime[4] */
224             4 +                 /* mtime[4] */
225             8 +                 /* length[8] */
226             8;                  /* minimum sum of string lengths */
227
228         if (wstat->name)
229                 size += strlen(wstat->name);
230         if (wstat->uid)
231                 size += strlen(wstat->uid);
232         if (wstat->gid)
233                 size += strlen(wstat->gid);
234         if (wstat->muid)
235                 size += strlen(wstat->muid);
236
237         if (extended) {
238                 size += 4 +     /* n_uid[4] */
239                     4 +         /* n_gid[4] */
240                     4 +         /* n_muid[4] */
241                     2;          /* string length of extension[4] */
242                 if (wstat->extension)
243                         size += strlen(wstat->extension);
244         }
245
246         return size;
247 }
248
249 /**
250  * buf_get_stat - safely decode a recieved metadata (stat) structure
251  * @bufp: buffer to deserialize
252  * @stat: metadata (stat) structure
253  * @extended: non-zero if 9P2000.u
254  *
255  */
256
257 static inline void
258 buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
259 {
260         stat->size = buf_get_int16(bufp);
261         stat->type = buf_get_int16(bufp);
262         stat->dev = buf_get_int32(bufp);
263         stat->qid.type = buf_get_int8(bufp);
264         stat->qid.version = buf_get_int32(bufp);
265         stat->qid.path = buf_get_int64(bufp);
266         stat->mode = buf_get_int32(bufp);
267         stat->atime = buf_get_int32(bufp);
268         stat->mtime = buf_get_int32(bufp);
269         stat->length = buf_get_int64(bufp);
270         buf_get_str(bufp, &stat->name);
271         buf_get_str(bufp, &stat->uid);
272         buf_get_str(bufp, &stat->gid);
273         buf_get_str(bufp, &stat->muid);
274
275         if (extended) {
276                 buf_get_str(bufp, &stat->extension);
277                 stat->n_uid = buf_get_int32(bufp);
278                 stat->n_gid = buf_get_int32(bufp);
279                 stat->n_muid = buf_get_int32(bufp);
280         }
281 }
282
283 /**
284  * v9fs_deserialize_stat - decode a received metadata structure
285  * @buf: buffer to deserialize
286  * @buflen: length of received buffer
287  * @stat: metadata structure to decode into
288  * @extended: non-zero if 9P2000.u
289  *
290  * Note: stat will point to the buf region.
291  */
292
293 int
294 v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
295                 int extended)
296 {
297         struct cbuf buffer;
298         struct cbuf *bufp = &buffer;
299         unsigned char *p;
300
301         buf_init(bufp, buf, buflen);
302         p = bufp->p;
303         buf_get_stat(bufp, stat, extended);
304
305         if (buf_check_overflow(bufp))
306                 return 0;
307         else
308                 return bufp->p - p;
309 }
310
311 /**
312  * deserialize_fcall - unmarshal a response
313  * @buf: recieved buffer
314  * @buflen: length of received buffer
315  * @rcall: fcall structure to populate
316  * @rcalllen: length of fcall structure to populate
317  * @extended: non-zero if 9P2000.u
318  *
319  */
320
321 int
322 v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
323                        int extended)
324 {
325
326         struct cbuf buffer;
327         struct cbuf *bufp = &buffer;
328         int i = 0;
329
330         buf_init(bufp, buf, buflen);
331
332         rcall->size = buf_get_int32(bufp);
333         rcall->id = buf_get_int8(bufp);
334         rcall->tag = buf_get_int16(bufp);
335
336         dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
337                 rcall->tag);
338
339         switch (rcall->id) {
340         default:
341                 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
342                 return -EPROTO;
343         case RVERSION:
344                 rcall->params.rversion.msize = buf_get_int32(bufp);
345                 buf_get_str(bufp, &rcall->params.rversion.version);
346                 break;
347         case RFLUSH:
348                 break;
349         case RATTACH:
350                 rcall->params.rattach.qid.type = buf_get_int8(bufp);
351                 rcall->params.rattach.qid.version = buf_get_int32(bufp);
352                 rcall->params.rattach.qid.path = buf_get_int64(bufp);
353                 break;
354         case RWALK:
355                 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
356                 if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
357                         eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
358                                 V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
359                         return -EPROTO;
360                 }
361
362                 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
363                         buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
364                 break;
365         case ROPEN:
366                 buf_get_qid(bufp, &rcall->params.ropen.qid);
367                 rcall->params.ropen.iounit = buf_get_int32(bufp);
368                 break;
369         case RCREATE:
370                 buf_get_qid(bufp, &rcall->params.rcreate.qid);
371                 rcall->params.rcreate.iounit = buf_get_int32(bufp);
372                 break;
373         case RREAD:
374                 rcall->params.rread.count = buf_get_int32(bufp);
375                 rcall->params.rread.data = bufp->p;
376                 buf_check_size(bufp, rcall->params.rread.count);
377                 break;
378         case RWRITE:
379                 rcall->params.rwrite.count = buf_get_int32(bufp);
380                 break;
381         case RCLUNK:
382                 break;
383         case RREMOVE:
384                 break;
385         case RSTAT:
386                 buf_get_int16(bufp);
387                 buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
388                 break;
389         case RWSTAT:
390                 break;
391         case RERROR:
392                 buf_get_str(bufp, &rcall->params.rerror.error);
393                 if (extended)
394                         rcall->params.rerror.errno = buf_get_int16(bufp);
395                 break;
396         }
397
398         if (buf_check_overflow(bufp)) {
399                 dprintk(DEBUG_ERROR, "buffer overflow\n");
400                 return -EIO;
401         }
402
403         return bufp->p - bufp->sp;
404 }
405
406 static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
407 {
408         *p = val;
409         buf_put_int8(bufp, val);
410 }
411
412 static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
413 {
414         *p = val;
415         buf_put_int16(bufp, val);
416 }
417
418 static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
419 {
420         *p = val;
421         buf_put_int32(bufp, val);
422 }
423
424 static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
425 {
426         *p = val;
427         buf_put_int64(bufp, val);
428 }
429
430 static inline void
431 v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
432 {
433         if (data) {
434                 str->len = strlen(data);
435                 str->str = bufp->p;
436         } else {
437                 str->len = 0;
438                 str->str = NULL;
439         }
440
441         buf_put_stringn(bufp, data, str->len);
442 }
443
444 static inline int
445 v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
446                    unsigned char **pdata)
447 {
448         *pdata = buf_alloc(bufp, count);
449         return copy_from_user(*pdata, data, count);
450 }
451
452 static void
453 v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
454                struct v9fs_stat *stat, int statsz, int extended)
455 {
456         v9fs_put_int16(bufp, statsz, &stat->size);
457         v9fs_put_int16(bufp, wstat->type, &stat->type);
458         v9fs_put_int32(bufp, wstat->dev, &stat->dev);
459         v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
460         v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
461         v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
462         v9fs_put_int32(bufp, wstat->mode, &stat->mode);
463         v9fs_put_int32(bufp, wstat->atime, &stat->atime);
464         v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
465         v9fs_put_int64(bufp, wstat->length, &stat->length);
466
467         v9fs_put_str(bufp, wstat->name, &stat->name);
468         v9fs_put_str(bufp, wstat->uid, &stat->uid);
469         v9fs_put_str(bufp, wstat->gid, &stat->gid);
470         v9fs_put_str(bufp, wstat->muid, &stat->muid);
471
472         if (extended) {
473                 v9fs_put_str(bufp, wstat->extension, &stat->extension);
474                 v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
475                 v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
476                 v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
477         }
478 }
479
480 static struct v9fs_fcall *
481 v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
482 {
483         struct v9fs_fcall *fc;
484
485         size += 4 + 1 + 2;      /* size[4] id[1] tag[2] */
486         fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
487         if (!fc)
488                 return ERR_PTR(-ENOMEM);
489
490         fc->sdata = (char *)fc + sizeof(*fc);
491
492         buf_init(bufp, (char *)fc->sdata, size);
493         v9fs_put_int32(bufp, size, &fc->size);
494         v9fs_put_int8(bufp, id, &fc->id);
495         v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
496
497         return fc;
498 }
499
500 void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
501 {
502         fc->tag = tag;
503         *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
504 }
505
506 struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
507 {
508         int size;
509         struct v9fs_fcall *fc;
510         struct cbuf buffer;
511         struct cbuf *bufp = &buffer;
512
513         size = 4 + 2 + strlen(version); /* msize[4] version[s] */
514         fc = v9fs_create_common(bufp, size, TVERSION);
515         if (IS_ERR(fc))
516                 goto error;
517
518         v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
519         v9fs_put_str(bufp, version, &fc->params.tversion.version);
520
521         if (buf_check_overflow(bufp)) {
522                 kfree(fc);
523                 fc = ERR_PTR(-ENOMEM);
524         }
525       error:
526         return fc;
527 }
528
529 struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
530 {
531         int size;
532         struct v9fs_fcall *fc;
533         struct cbuf buffer;
534         struct cbuf *bufp = &buffer;
535
536         size = 4 + 2 + strlen(uname) + 2 + strlen(aname);       /* afid[4] uname[s] aname[s] */
537         fc = v9fs_create_common(bufp, size, TAUTH);
538         if (IS_ERR(fc))
539                 goto error;
540
541         v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
542         v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
543         v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
544
545         if (buf_check_overflow(bufp)) {
546                 kfree(fc);
547                 fc = ERR_PTR(-ENOMEM);
548         }
549       error:
550         return fc;
551 }
552
553 struct v9fs_fcall *
554 v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
555 {
556         int size;
557         struct v9fs_fcall *fc;
558         struct cbuf buffer;
559         struct cbuf *bufp = &buffer;
560
561         size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname);   /* fid[4] afid[4] uname[s] aname[s] */
562         fc = v9fs_create_common(bufp, size, TATTACH);
563         if (IS_ERR(fc))
564                 goto error;
565
566         v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
567         v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
568         v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
569         v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
570
571       error:
572         return fc;
573 }
574
575 struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
576 {
577         int size;
578         struct v9fs_fcall *fc;
579         struct cbuf buffer;
580         struct cbuf *bufp = &buffer;
581
582         size = 2;               /* oldtag[2] */
583         fc = v9fs_create_common(bufp, size, TFLUSH);
584         if (IS_ERR(fc))
585                 goto error;
586
587         v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
588
589         if (buf_check_overflow(bufp)) {
590                 kfree(fc);
591                 fc = ERR_PTR(-ENOMEM);
592         }
593       error:
594         return fc;
595 }
596
597 struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
598                                      char **wnames)
599 {
600         int i, size;
601         struct v9fs_fcall *fc;
602         struct cbuf buffer;
603         struct cbuf *bufp = &buffer;
604
605         if (nwname > V9FS_MAXWELEM) {
606                 dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
607                 return NULL;
608         }
609
610         size = 4 + 4 + 2;       /* fid[4] newfid[4] nwname[2] ... */
611         for (i = 0; i < nwname; i++) {
612                 size += 2 + strlen(wnames[i]);  /* wname[s] */
613         }
614
615         fc = v9fs_create_common(bufp, size, TWALK);
616         if (IS_ERR(fc))
617                 goto error;
618
619         v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
620         v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
621         v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
622         for (i = 0; i < nwname; i++) {
623                 v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
624         }
625
626         if (buf_check_overflow(bufp)) {
627                 kfree(fc);
628                 fc = ERR_PTR(-ENOMEM);
629         }
630       error:
631         return fc;
632 }
633
634 struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
635 {
636         int size;
637         struct v9fs_fcall *fc;
638         struct cbuf buffer;
639         struct cbuf *bufp = &buffer;
640
641         size = 4 + 1;           /* fid[4] mode[1] */
642         fc = v9fs_create_common(bufp, size, TOPEN);
643         if (IS_ERR(fc))
644                 goto error;
645
646         v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
647         v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
648
649         if (buf_check_overflow(bufp)) {
650                 kfree(fc);
651                 fc = ERR_PTR(-ENOMEM);
652         }
653       error:
654         return fc;
655 }
656
657 struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode)
658 {
659         int size;
660         struct v9fs_fcall *fc;
661         struct cbuf buffer;
662         struct cbuf *bufp = &buffer;
663
664         size = 4 + 2 + strlen(name) + 4 + 1;    /* fid[4] name[s] perm[4] mode[1] */
665         fc = v9fs_create_common(bufp, size, TCREATE);
666         if (IS_ERR(fc))
667                 goto error;
668
669         v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
670         v9fs_put_str(bufp, name, &fc->params.tcreate.name);
671         v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
672         v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
673
674         if (buf_check_overflow(bufp)) {
675                 kfree(fc);
676                 fc = ERR_PTR(-ENOMEM);
677         }
678       error:
679         return fc;
680 }
681
682 struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
683 {
684         int size;
685         struct v9fs_fcall *fc;
686         struct cbuf buffer;
687         struct cbuf *bufp = &buffer;
688
689         size = 4 + 8 + 4;       /* fid[4] offset[8] count[4] */
690         fc = v9fs_create_common(bufp, size, TREAD);
691         if (IS_ERR(fc))
692                 goto error;
693
694         v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
695         v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
696         v9fs_put_int32(bufp, count, &fc->params.tread.count);
697
698         if (buf_check_overflow(bufp)) {
699                 kfree(fc);
700                 fc = ERR_PTR(-ENOMEM);
701         }
702       error:
703         return fc;
704 }
705
706 struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
707                                       const char __user * data)
708 {
709         int size, err;
710         struct v9fs_fcall *fc;
711         struct cbuf buffer;
712         struct cbuf *bufp = &buffer;
713
714         size = 4 + 8 + 4 + count;       /* fid[4] offset[8] count[4] data[count] */
715         fc = v9fs_create_common(bufp, size, TWRITE);
716         if (IS_ERR(fc))
717                 goto error;
718
719         v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
720         v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
721         v9fs_put_int32(bufp, count, &fc->params.twrite.count);
722         err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
723         if (err) {
724                 kfree(fc);
725                 fc = ERR_PTR(err);
726         }
727
728         if (buf_check_overflow(bufp)) {
729                 kfree(fc);
730                 fc = ERR_PTR(-ENOMEM);
731         }
732       error:
733         return fc;
734 }
735
736 struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
737 {
738         int size;
739         struct v9fs_fcall *fc;
740         struct cbuf buffer;
741         struct cbuf *bufp = &buffer;
742
743         size = 4;               /* fid[4] */
744         fc = v9fs_create_common(bufp, size, TCLUNK);
745         if (IS_ERR(fc))
746                 goto error;
747
748         v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
749
750         if (buf_check_overflow(bufp)) {
751                 kfree(fc);
752                 fc = ERR_PTR(-ENOMEM);
753         }
754       error:
755         return fc;
756 }
757
758 struct v9fs_fcall *v9fs_create_tremove(u32 fid)
759 {
760         int size;
761         struct v9fs_fcall *fc;
762         struct cbuf buffer;
763         struct cbuf *bufp = &buffer;
764
765         size = 4;               /* fid[4] */
766         fc = v9fs_create_common(bufp, size, TREMOVE);
767         if (IS_ERR(fc))
768                 goto error;
769
770         v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
771
772         if (buf_check_overflow(bufp)) {
773                 kfree(fc);
774                 fc = ERR_PTR(-ENOMEM);
775         }
776       error:
777         return fc;
778 }
779
780 struct v9fs_fcall *v9fs_create_tstat(u32 fid)
781 {
782         int size;
783         struct v9fs_fcall *fc;
784         struct cbuf buffer;
785         struct cbuf *bufp = &buffer;
786
787         size = 4;               /* fid[4] */
788         fc = v9fs_create_common(bufp, size, TSTAT);
789         if (IS_ERR(fc))
790                 goto error;
791
792         v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
793
794         if (buf_check_overflow(bufp)) {
795                 kfree(fc);
796                 fc = ERR_PTR(-ENOMEM);
797         }
798       error:
799         return fc;
800 }
801
802 struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
803                                       int extended)
804 {
805         int size, statsz;
806         struct v9fs_fcall *fc;
807         struct cbuf buffer;
808         struct cbuf *bufp = &buffer;
809
810         statsz = v9fs_size_wstat(wstat, extended);
811         size = 4 + 2 + 2 + statsz;      /* fid[4] stat[n] */
812         fc = v9fs_create_common(bufp, size, TWSTAT);
813         if (IS_ERR(fc))
814                 goto error;
815
816         v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
817         buf_put_int16(bufp, statsz + 2);
818         v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
819
820         if (buf_check_overflow(bufp)) {
821                 kfree(fc);
822                 fc = ERR_PTR(-ENOMEM);
823         }
824       error:
825         return fc;
826 }