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 */
41struct cbuf {
42	unsigned char *sp;
43	unsigned char *p;
44	unsigned char *ep;
45};
46
47static 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
53static inline int buf_check_overflow(struct cbuf *buf)
54{
55	return buf->p > buf->ep;
56}
57
58static 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
74static 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
86static 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
94static 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
102static 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
110static 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
118static 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
133static inline void buf_put_string(struct cbuf *buf, const char *s)
134{
135	buf_put_stringn(buf, s, strlen(s));
136}
137
138static 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
150static 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
162static 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
174static 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
186static 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
198static 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
212static 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
262static void
263buf_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
298int
299v9fs_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
326int
327v9fs_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
411static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
412{
413	*p = val;
414	buf_put_int8(bufp, val);
415}
416
417static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
418{
419	*p = val;
420	buf_put_int16(bufp, val);
421}
422
423static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
424{
425	*p = val;
426	buf_put_int32(bufp, val);
427}
428
429static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
430{
431	*p = val;
432	buf_put_int64(bufp, val);
433}
434
435static void
436v9fs_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
453static int
454v9fs_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
461static void
462v9fs_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
489static struct v9fs_fcall *
490v9fs_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
509void 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
515struct 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
539struct v9fs_fcall *
540v9fs_create_tattach(u32 fid, 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 + 4 + 2 + strlen(uname) + 2 + strlen(aname);	/* fid[4] afid[4] uname[s] aname[s] */
548	fc = v9fs_create_common(bufp, size, TATTACH);
549	if (IS_ERR(fc))
550		goto error;
551
552	v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
553	v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
554	v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
555	v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
556
557      error:
558	return fc;
559}
560
561struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
562{
563	int size;
564	struct v9fs_fcall *fc;
565	struct cbuf buffer;
566	struct cbuf *bufp = &buffer;
567
568	size = 2;		/* oldtag[2] */
569	fc = v9fs_create_common(bufp, size, TFLUSH);
570	if (IS_ERR(fc))
571		goto error;
572
573	v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
574
575	if (buf_check_overflow(bufp)) {
576		kfree(fc);
577		fc = ERR_PTR(-ENOMEM);
578	}
579      error:
580	return fc;
581}
582
583struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
584				     char **wnames)
585{
586	int i, size;
587	struct v9fs_fcall *fc;
588	struct cbuf buffer;
589	struct cbuf *bufp = &buffer;
590
591	if (nwname > V9FS_MAXWELEM) {
592		dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
593		return NULL;
594	}
595
596	size = 4 + 4 + 2;	/* fid[4] newfid[4] nwname[2] ... */
597	for (i = 0; i < nwname; i++) {
598		size += 2 + strlen(wnames[i]);	/* wname[s] */
599	}
600
601	fc = v9fs_create_common(bufp, size, TWALK);
602	if (IS_ERR(fc))
603		goto error;
604
605	v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
606	v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
607	v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
608	for (i = 0; i < nwname; i++) {
609		v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
610	}
611
612	if (buf_check_overflow(bufp)) {
613		kfree(fc);
614		fc = ERR_PTR(-ENOMEM);
615	}
616      error:
617	return fc;
618}
619
620struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
621{
622	int size;
623	struct v9fs_fcall *fc;
624	struct cbuf buffer;
625	struct cbuf *bufp = &buffer;
626
627	size = 4 + 1;		/* fid[4] mode[1] */
628	fc = v9fs_create_common(bufp, size, TOPEN);
629	if (IS_ERR(fc))
630		goto error;
631
632	v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
633	v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
634
635	if (buf_check_overflow(bufp)) {
636		kfree(fc);
637		fc = ERR_PTR(-ENOMEM);
638	}
639      error:
640	return fc;
641}
642
643struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
644	char *extension, int extended)
645{
646	int size;
647	struct v9fs_fcall *fc;
648	struct cbuf buffer;
649	struct cbuf *bufp = &buffer;
650
651	size = 4 + 2 + strlen(name) + 4 + 1;	/* fid[4] name[s] perm[4] mode[1] */
652	if (extended) {
653		size += 2 +			/* extension[s] */
654		    (extension == NULL ? 0 : strlen(extension));
655	}
656
657	fc = v9fs_create_common(bufp, size, TCREATE);
658	if (IS_ERR(fc))
659		goto error;
660
661	v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
662	v9fs_put_str(bufp, name, &fc->params.tcreate.name);
663	v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
664	v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
665	if (extended)
666		v9fs_put_str(bufp, extension, &fc->params.tcreate.extension);
667
668	if (buf_check_overflow(bufp)) {
669		kfree(fc);
670		fc = ERR_PTR(-ENOMEM);
671	}
672      error:
673	return fc;
674}
675
676struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
677{
678	int size;
679	struct v9fs_fcall *fc;
680	struct cbuf buffer;
681	struct cbuf *bufp = &buffer;
682
683	size = 4 + 8 + 4;	/* fid[4] offset[8] count[4] */
684	fc = v9fs_create_common(bufp, size, TREAD);
685	if (IS_ERR(fc))
686		goto error;
687
688	v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
689	v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
690	v9fs_put_int32(bufp, count, &fc->params.tread.count);
691
692	if (buf_check_overflow(bufp)) {
693		kfree(fc);
694		fc = ERR_PTR(-ENOMEM);
695	}
696      error:
697	return fc;
698}
699
700struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
701				      const char __user * data)
702{
703	int size, err;
704	struct v9fs_fcall *fc;
705	struct cbuf buffer;
706	struct cbuf *bufp = &buffer;
707
708	size = 4 + 8 + 4 + count;	/* fid[4] offset[8] count[4] data[count] */
709	fc = v9fs_create_common(bufp, size, TWRITE);
710	if (IS_ERR(fc))
711		goto error;
712
713	v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
714	v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
715	v9fs_put_int32(bufp, count, &fc->params.twrite.count);
716	err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
717	if (err) {
718		kfree(fc);
719		fc = ERR_PTR(err);
720	}
721
722	if (buf_check_overflow(bufp)) {
723		kfree(fc);
724		fc = ERR_PTR(-ENOMEM);
725	}
726      error:
727	return fc;
728}
729
730struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
731{
732	int size;
733	struct v9fs_fcall *fc;
734	struct cbuf buffer;
735	struct cbuf *bufp = &buffer;
736
737	size = 4;		/* fid[4] */
738	fc = v9fs_create_common(bufp, size, TCLUNK);
739	if (IS_ERR(fc))
740		goto error;
741
742	v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
743
744	if (buf_check_overflow(bufp)) {
745		kfree(fc);
746		fc = ERR_PTR(-ENOMEM);
747	}
748      error:
749	return fc;
750}
751
752struct v9fs_fcall *v9fs_create_tremove(u32 fid)
753{
754	int size;
755	struct v9fs_fcall *fc;
756	struct cbuf buffer;
757	struct cbuf *bufp = &buffer;
758
759	size = 4;		/* fid[4] */
760	fc = v9fs_create_common(bufp, size, TREMOVE);
761	if (IS_ERR(fc))
762		goto error;
763
764	v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
765
766	if (buf_check_overflow(bufp)) {
767		kfree(fc);
768		fc = ERR_PTR(-ENOMEM);
769	}
770      error:
771	return fc;
772}
773
774struct v9fs_fcall *v9fs_create_tstat(u32 fid)
775{
776	int size;
777	struct v9fs_fcall *fc;
778	struct cbuf buffer;
779	struct cbuf *bufp = &buffer;
780
781	size = 4;		/* fid[4] */
782	fc = v9fs_create_common(bufp, size, TSTAT);
783	if (IS_ERR(fc))
784		goto error;
785
786	v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
787
788	if (buf_check_overflow(bufp)) {
789		kfree(fc);
790		fc = ERR_PTR(-ENOMEM);
791	}
792      error:
793	return fc;
794}
795
796struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
797				      int extended)
798{
799	int size, statsz;
800	struct v9fs_fcall *fc;
801	struct cbuf buffer;
802	struct cbuf *bufp = &buffer;
803
804	statsz = v9fs_size_wstat(wstat, extended);
805	size = 4 + 2 + 2 + statsz;	/* fid[4] stat[n] */
806	fc = v9fs_create_common(bufp, size, TWSTAT);
807	if (IS_ERR(fc))
808		goto error;
809
810	v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
811	buf_put_int16(bufp, statsz + 2);
812	v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
813
814	if (buf_check_overflow(bufp)) {
815		kfree(fc);
816		fc = ERR_PTR(-ENOMEM);
817	}
818      error:
819	return fc;
820}
821