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