[PATCH] v9fs: add extension field to Tcreate
[pandora-kernel.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 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 #if 0
540 struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
541 {
542         int size;
543         struct v9fs_fcall *fc;
544         struct cbuf buffer;
545         struct cbuf *bufp = &buffer;
546
547         size = 4 + 2 + strlen(uname) + 2 + strlen(aname);       /* afid[4] uname[s] aname[s] */
548         fc = v9fs_create_common(bufp, size, TAUTH);
549         if (IS_ERR(fc))
550                 goto error;
551
552         v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
553         v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
554         v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
555
556         if (buf_check_overflow(bufp)) {
557                 kfree(fc);
558                 fc = ERR_PTR(-ENOMEM);
559         }
560       error:
561         return fc;
562 }
563 #endif  /*  0  */
564
565 struct v9fs_fcall *
566 v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
567 {
568         int size;
569         struct v9fs_fcall *fc;
570         struct cbuf buffer;
571         struct cbuf *bufp = &buffer;
572
573         size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname);   /* fid[4] afid[4] uname[s] aname[s] */
574         fc = v9fs_create_common(bufp, size, TATTACH);
575         if (IS_ERR(fc))
576                 goto error;
577
578         v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
579         v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
580         v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
581         v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
582
583       error:
584         return fc;
585 }
586
587 struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
588 {
589         int size;
590         struct v9fs_fcall *fc;
591         struct cbuf buffer;
592         struct cbuf *bufp = &buffer;
593
594         size = 2;               /* oldtag[2] */
595         fc = v9fs_create_common(bufp, size, TFLUSH);
596         if (IS_ERR(fc))
597                 goto error;
598
599         v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
600
601         if (buf_check_overflow(bufp)) {
602                 kfree(fc);
603                 fc = ERR_PTR(-ENOMEM);
604         }
605       error:
606         return fc;
607 }
608
609 struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
610                                      char **wnames)
611 {
612         int i, size;
613         struct v9fs_fcall *fc;
614         struct cbuf buffer;
615         struct cbuf *bufp = &buffer;
616
617         if (nwname > V9FS_MAXWELEM) {
618                 dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
619                 return NULL;
620         }
621
622         size = 4 + 4 + 2;       /* fid[4] newfid[4] nwname[2] ... */
623         for (i = 0; i < nwname; i++) {
624                 size += 2 + strlen(wnames[i]);  /* wname[s] */
625         }
626
627         fc = v9fs_create_common(bufp, size, TWALK);
628         if (IS_ERR(fc))
629                 goto error;
630
631         v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
632         v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
633         v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
634         for (i = 0; i < nwname; i++) {
635                 v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
636         }
637
638         if (buf_check_overflow(bufp)) {
639                 kfree(fc);
640                 fc = ERR_PTR(-ENOMEM);
641         }
642       error:
643         return fc;
644 }
645
646 struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
647 {
648         int size;
649         struct v9fs_fcall *fc;
650         struct cbuf buffer;
651         struct cbuf *bufp = &buffer;
652
653         size = 4 + 1;           /* fid[4] mode[1] */
654         fc = v9fs_create_common(bufp, size, TOPEN);
655         if (IS_ERR(fc))
656                 goto error;
657
658         v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
659         v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
660
661         if (buf_check_overflow(bufp)) {
662                 kfree(fc);
663                 fc = ERR_PTR(-ENOMEM);
664         }
665       error:
666         return fc;
667 }
668
669 struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
670         char *extension, int extended)
671 {
672         int size;
673         struct v9fs_fcall *fc;
674         struct cbuf buffer;
675         struct cbuf *bufp = &buffer;
676
677         size = 4 + 2 + strlen(name) + 4 + 1;    /* fid[4] name[s] perm[4] mode[1] */
678         if (extended && extension!=NULL)
679                 size += 2 + strlen(extension);  /* extension[s] */
680
681         fc = v9fs_create_common(bufp, size, TCREATE);
682         if (IS_ERR(fc))
683                 goto error;
684
685         v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
686         v9fs_put_str(bufp, name, &fc->params.tcreate.name);
687         v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
688         v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
689         if (extended)
690                 v9fs_put_str(bufp, extension, &fc->params.tcreate.extension);
691
692         if (buf_check_overflow(bufp)) {
693                 kfree(fc);
694                 fc = ERR_PTR(-ENOMEM);
695         }
696       error:
697         return fc;
698 }
699
700 struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
701 {
702         int size;
703         struct v9fs_fcall *fc;
704         struct cbuf buffer;
705         struct cbuf *bufp = &buffer;
706
707         size = 4 + 8 + 4;       /* fid[4] offset[8] count[4] */
708         fc = v9fs_create_common(bufp, size, TREAD);
709         if (IS_ERR(fc))
710                 goto error;
711
712         v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
713         v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
714         v9fs_put_int32(bufp, count, &fc->params.tread.count);
715
716         if (buf_check_overflow(bufp)) {
717                 kfree(fc);
718                 fc = ERR_PTR(-ENOMEM);
719         }
720       error:
721         return fc;
722 }
723
724 struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
725                                       const char __user * data)
726 {
727         int size, err;
728         struct v9fs_fcall *fc;
729         struct cbuf buffer;
730         struct cbuf *bufp = &buffer;
731
732         size = 4 + 8 + 4 + count;       /* fid[4] offset[8] count[4] data[count] */
733         fc = v9fs_create_common(bufp, size, TWRITE);
734         if (IS_ERR(fc))
735                 goto error;
736
737         v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
738         v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
739         v9fs_put_int32(bufp, count, &fc->params.twrite.count);
740         err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
741         if (err) {
742                 kfree(fc);
743                 fc = ERR_PTR(err);
744         }
745
746         if (buf_check_overflow(bufp)) {
747                 kfree(fc);
748                 fc = ERR_PTR(-ENOMEM);
749         }
750       error:
751         return fc;
752 }
753
754 struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
755 {
756         int size;
757         struct v9fs_fcall *fc;
758         struct cbuf buffer;
759         struct cbuf *bufp = &buffer;
760
761         size = 4;               /* fid[4] */
762         fc = v9fs_create_common(bufp, size, TCLUNK);
763         if (IS_ERR(fc))
764                 goto error;
765
766         v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
767
768         if (buf_check_overflow(bufp)) {
769                 kfree(fc);
770                 fc = ERR_PTR(-ENOMEM);
771         }
772       error:
773         return fc;
774 }
775
776 struct v9fs_fcall *v9fs_create_tremove(u32 fid)
777 {
778         int size;
779         struct v9fs_fcall *fc;
780         struct cbuf buffer;
781         struct cbuf *bufp = &buffer;
782
783         size = 4;               /* fid[4] */
784         fc = v9fs_create_common(bufp, size, TREMOVE);
785         if (IS_ERR(fc))
786                 goto error;
787
788         v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
789
790         if (buf_check_overflow(bufp)) {
791                 kfree(fc);
792                 fc = ERR_PTR(-ENOMEM);
793         }
794       error:
795         return fc;
796 }
797
798 struct v9fs_fcall *v9fs_create_tstat(u32 fid)
799 {
800         int size;
801         struct v9fs_fcall *fc;
802         struct cbuf buffer;
803         struct cbuf *bufp = &buffer;
804
805         size = 4;               /* fid[4] */
806         fc = v9fs_create_common(bufp, size, TSTAT);
807         if (IS_ERR(fc))
808                 goto error;
809
810         v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
811
812         if (buf_check_overflow(bufp)) {
813                 kfree(fc);
814                 fc = ERR_PTR(-ENOMEM);
815         }
816       error:
817         return fc;
818 }
819
820 struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
821                                       int extended)
822 {
823         int size, statsz;
824         struct v9fs_fcall *fc;
825         struct cbuf buffer;
826         struct cbuf *bufp = &buffer;
827
828         statsz = v9fs_size_wstat(wstat, extended);
829         size = 4 + 2 + 2 + statsz;      /* fid[4] stat[n] */
830         fc = v9fs_create_common(bufp, size, TWSTAT);
831         if (IS_ERR(fc))
832                 goto error;
833
834         v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
835         buf_put_int16(bufp, statsz + 2);
836         v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
837
838         if (buf_check_overflow(bufp)) {
839                 kfree(fc);
840                 fc = ERR_PTR(-ENOMEM);
841         }
842       error:
843         return fc;
844 }