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