[PATCH] Kprobes: Fix deadlock in function-return probes
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / 9p / conv.c
blob32a9f99154e23b30bb804ba6601b6f804c9baff5
1 /*
2 * linux/fs/9p/conv.c
4 * 9P protocol conversion functions
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>
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.
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.
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
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"
40 * Buffer to help with string parsing
42 struct cbuf {
43 unsigned char *sp;
44 unsigned char *p;
45 unsigned char *ep;
48 static inline void buf_init(struct cbuf *buf, void *data, int datalen)
50 buf->sp = buf->p = data;
51 buf->ep = data + datalen;
54 static inline int buf_check_overflow(struct cbuf *buf)
56 return buf->p > buf->ep;
59 static int buf_check_size(struct cbuf *buf, int len)
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;
69 return 0;
72 return 1;
75 static void *buf_alloc(struct cbuf *buf, int len)
77 void *ret = NULL;
79 if (buf_check_size(buf, len)) {
80 ret = buf->p;
81 buf->p += len;
84 return ret;
87 static void buf_put_int8(struct cbuf *buf, u8 val)
89 if (buf_check_size(buf, 1)) {
90 buf->p[0] = val;
91 buf->p++;
95 static void buf_put_int16(struct cbuf *buf, u16 val)
97 if (buf_check_size(buf, 2)) {
98 *(__le16 *) buf->p = cpu_to_le16(val);
99 buf->p += 2;
103 static void buf_put_int32(struct cbuf *buf, u32 val)
105 if (buf_check_size(buf, 4)) {
106 *(__le32 *)buf->p = cpu_to_le32(val);
107 buf->p += 4;
111 static void buf_put_int64(struct cbuf *buf, u64 val)
113 if (buf_check_size(buf, 8)) {
114 *(__le64 *)buf->p = cpu_to_le64(val);
115 buf->p += 8;
119 static void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
121 if (buf_check_size(buf, slen + 2)) {
122 buf_put_int16(buf, slen);
123 memcpy(buf->p, s, slen);
124 buf->p += slen;
128 static inline void buf_put_string(struct cbuf *buf, const char *s)
130 buf_put_stringn(buf, s, strlen(s));
133 static u8 buf_get_int8(struct cbuf *buf)
135 u8 ret = 0;
137 if (buf_check_size(buf, 1)) {
138 ret = buf->p[0];
139 buf->p++;
142 return ret;
145 static u16 buf_get_int16(struct cbuf *buf)
147 u16 ret = 0;
149 if (buf_check_size(buf, 2)) {
150 ret = le16_to_cpu(*(__le16 *)buf->p);
151 buf->p += 2;
154 return ret;
157 static u32 buf_get_int32(struct cbuf *buf)
159 u32 ret = 0;
161 if (buf_check_size(buf, 4)) {
162 ret = le32_to_cpu(*(__le32 *)buf->p);
163 buf->p += 4;
166 return ret;
169 static u64 buf_get_int64(struct cbuf *buf)
171 u64 ret = 0;
173 if (buf_check_size(buf, 8)) {
174 ret = le64_to_cpu(*(__le64 *)buf->p);
175 buf->p += 8;
178 return ret;
181 static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
183 vstr->len = buf_get_int16(buf);
184 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
185 vstr->str = buf->p;
186 buf->p += vstr->len;
187 } else {
188 vstr->len = 0;
189 vstr->str = NULL;
193 static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
195 qid->type = buf_get_int8(bufp);
196 qid->version = buf_get_int32(bufp);
197 qid->path = buf_get_int64(bufp);
201 * v9fs_size_wstat - calculate the size of a variable length stat struct
202 * @stat: metadata (stat) structure
203 * @extended: non-zero if 9P2000.u
207 static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
209 int size = 0;
211 if (wstat == NULL) {
212 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
213 return 0;
216 size = /* 2 + *//* size[2] */
217 2 + /* type[2] */
218 4 + /* dev[4] */
219 1 + /* qid.type[1] */
220 4 + /* qid.vers[4] */
221 8 + /* qid.path[8] */
222 4 + /* mode[4] */
223 4 + /* atime[4] */
224 4 + /* mtime[4] */
225 8 + /* length[8] */
226 8; /* minimum sum of string lengths */
228 if (wstat->name)
229 size += strlen(wstat->name);
230 if (wstat->uid)
231 size += strlen(wstat->uid);
232 if (wstat->gid)
233 size += strlen(wstat->gid);
234 if (wstat->muid)
235 size += strlen(wstat->muid);
237 if (extended) {
238 size += 4 + /* n_uid[4] */
239 4 + /* n_gid[4] */
240 4 + /* n_muid[4] */
241 2; /* string length of extension[4] */
242 if (wstat->extension)
243 size += strlen(wstat->extension);
246 return size;
250 * buf_get_stat - safely decode a recieved metadata (stat) structure
251 * @bufp: buffer to deserialize
252 * @stat: metadata (stat) structure
253 * @extended: non-zero if 9P2000.u
257 static void
258 buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
260 stat->size = buf_get_int16(bufp);
261 stat->type = buf_get_int16(bufp);
262 stat->dev = buf_get_int32(bufp);
263 stat->qid.type = buf_get_int8(bufp);
264 stat->qid.version = buf_get_int32(bufp);
265 stat->qid.path = buf_get_int64(bufp);
266 stat->mode = buf_get_int32(bufp);
267 stat->atime = buf_get_int32(bufp);
268 stat->mtime = buf_get_int32(bufp);
269 stat->length = buf_get_int64(bufp);
270 buf_get_str(bufp, &stat->name);
271 buf_get_str(bufp, &stat->uid);
272 buf_get_str(bufp, &stat->gid);
273 buf_get_str(bufp, &stat->muid);
275 if (extended) {
276 buf_get_str(bufp, &stat->extension);
277 stat->n_uid = buf_get_int32(bufp);
278 stat->n_gid = buf_get_int32(bufp);
279 stat->n_muid = buf_get_int32(bufp);
284 * v9fs_deserialize_stat - decode a received metadata structure
285 * @buf: buffer to deserialize
286 * @buflen: length of received buffer
287 * @stat: metadata structure to decode into
288 * @extended: non-zero if 9P2000.u
290 * Note: stat will point to the buf region.
294 v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
295 int extended)
297 struct cbuf buffer;
298 struct cbuf *bufp = &buffer;
299 unsigned char *p;
301 buf_init(bufp, buf, buflen);
302 p = bufp->p;
303 buf_get_stat(bufp, stat, extended);
305 if (buf_check_overflow(bufp))
306 return 0;
307 else
308 return bufp->p - p;
312 * deserialize_fcall - unmarshal a response
313 * @buf: recieved buffer
314 * @buflen: length of received buffer
315 * @rcall: fcall structure to populate
316 * @rcalllen: length of fcall structure to populate
317 * @extended: non-zero if 9P2000.u
322 v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
323 int extended)
326 struct cbuf buffer;
327 struct cbuf *bufp = &buffer;
328 int i = 0;
330 buf_init(bufp, buf, buflen);
332 rcall->size = buf_get_int32(bufp);
333 rcall->id = buf_get_int8(bufp);
334 rcall->tag = buf_get_int16(bufp);
336 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
337 rcall->tag);
339 switch (rcall->id) {
340 default:
341 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
342 return -EPROTO;
343 case RVERSION:
344 rcall->params.rversion.msize = buf_get_int32(bufp);
345 buf_get_str(bufp, &rcall->params.rversion.version);
346 break;
347 case RFLUSH:
348 break;
349 case RATTACH:
350 rcall->params.rattach.qid.type = buf_get_int8(bufp);
351 rcall->params.rattach.qid.version = buf_get_int32(bufp);
352 rcall->params.rattach.qid.path = buf_get_int64(bufp);
353 break;
354 case RWALK:
355 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
356 if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
357 eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
358 V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
359 return -EPROTO;
362 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
363 buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
364 break;
365 case ROPEN:
366 buf_get_qid(bufp, &rcall->params.ropen.qid);
367 rcall->params.ropen.iounit = buf_get_int32(bufp);
368 break;
369 case RCREATE:
370 buf_get_qid(bufp, &rcall->params.rcreate.qid);
371 rcall->params.rcreate.iounit = buf_get_int32(bufp);
372 break;
373 case RREAD:
374 rcall->params.rread.count = buf_get_int32(bufp);
375 rcall->params.rread.data = bufp->p;
376 buf_check_size(bufp, rcall->params.rread.count);
377 break;
378 case RWRITE:
379 rcall->params.rwrite.count = buf_get_int32(bufp);
380 break;
381 case RCLUNK:
382 break;
383 case RREMOVE:
384 break;
385 case RSTAT:
386 buf_get_int16(bufp);
387 buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
388 break;
389 case RWSTAT:
390 break;
391 case RERROR:
392 buf_get_str(bufp, &rcall->params.rerror.error);
393 if (extended)
394 rcall->params.rerror.errno = buf_get_int16(bufp);
395 break;
398 if (buf_check_overflow(bufp)) {
399 dprintk(DEBUG_ERROR, "buffer overflow\n");
400 return -EIO;
403 return bufp->p - bufp->sp;
406 static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
408 *p = val;
409 buf_put_int8(bufp, val);
412 static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
414 *p = val;
415 buf_put_int16(bufp, val);
418 static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
420 *p = val;
421 buf_put_int32(bufp, val);
424 static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
426 *p = val;
427 buf_put_int64(bufp, val);
430 static void
431 v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
433 if (data) {
434 str->len = strlen(data);
435 str->str = bufp->p;
436 } else {
437 str->len = 0;
438 str->str = NULL;
441 buf_put_stringn(bufp, data, str->len);
444 static int
445 v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
446 unsigned char **pdata)
448 *pdata = buf_alloc(bufp, count);
449 return copy_from_user(*pdata, data, count);
452 static void
453 v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
454 struct v9fs_stat *stat, int statsz, int extended)
456 v9fs_put_int16(bufp, statsz, &stat->size);
457 v9fs_put_int16(bufp, wstat->type, &stat->type);
458 v9fs_put_int32(bufp, wstat->dev, &stat->dev);
459 v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
460 v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
461 v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
462 v9fs_put_int32(bufp, wstat->mode, &stat->mode);
463 v9fs_put_int32(bufp, wstat->atime, &stat->atime);
464 v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
465 v9fs_put_int64(bufp, wstat->length, &stat->length);
467 v9fs_put_str(bufp, wstat->name, &stat->name);
468 v9fs_put_str(bufp, wstat->uid, &stat->uid);
469 v9fs_put_str(bufp, wstat->gid, &stat->gid);
470 v9fs_put_str(bufp, wstat->muid, &stat->muid);
472 if (extended) {
473 v9fs_put_str(bufp, wstat->extension, &stat->extension);
474 v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
475 v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
476 v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
480 static struct v9fs_fcall *
481 v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
483 struct v9fs_fcall *fc;
485 size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
486 fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
487 if (!fc)
488 return ERR_PTR(-ENOMEM);
490 fc->sdata = (char *)fc + sizeof(*fc);
492 buf_init(bufp, (char *)fc->sdata, size);
493 v9fs_put_int32(bufp, size, &fc->size);
494 v9fs_put_int8(bufp, id, &fc->id);
495 v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
497 return fc;
500 void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
502 fc->tag = tag;
503 *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
506 struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
508 int size;
509 struct v9fs_fcall *fc;
510 struct cbuf buffer;
511 struct cbuf *bufp = &buffer;
513 size = 4 + 2 + strlen(version); /* msize[4] version[s] */
514 fc = v9fs_create_common(bufp, size, TVERSION);
515 if (IS_ERR(fc))
516 goto error;
518 v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
519 v9fs_put_str(bufp, version, &fc->params.tversion.version);
521 if (buf_check_overflow(bufp)) {
522 kfree(fc);
523 fc = ERR_PTR(-ENOMEM);
525 error:
526 return fc;
529 struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
531 int size;
532 struct v9fs_fcall *fc;
533 struct cbuf buffer;
534 struct cbuf *bufp = &buffer;
536 size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */
537 fc = v9fs_create_common(bufp, size, TAUTH);
538 if (IS_ERR(fc))
539 goto error;
541 v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
542 v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
543 v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
545 if (buf_check_overflow(bufp)) {
546 kfree(fc);
547 fc = ERR_PTR(-ENOMEM);
549 error:
550 return fc;
553 struct v9fs_fcall *
554 v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
556 int size;
557 struct v9fs_fcall *fc;
558 struct cbuf buffer;
559 struct cbuf *bufp = &buffer;
561 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */
562 fc = v9fs_create_common(bufp, size, TATTACH);
563 if (IS_ERR(fc))
564 goto error;
566 v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
567 v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
568 v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
569 v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
571 error:
572 return fc;
575 struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
577 int size;
578 struct v9fs_fcall *fc;
579 struct cbuf buffer;
580 struct cbuf *bufp = &buffer;
582 size = 2; /* oldtag[2] */
583 fc = v9fs_create_common(bufp, size, TFLUSH);
584 if (IS_ERR(fc))
585 goto error;
587 v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
589 if (buf_check_overflow(bufp)) {
590 kfree(fc);
591 fc = ERR_PTR(-ENOMEM);
593 error:
594 return fc;
597 struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
598 char **wnames)
600 int i, size;
601 struct v9fs_fcall *fc;
602 struct cbuf buffer;
603 struct cbuf *bufp = &buffer;
605 if (nwname > V9FS_MAXWELEM) {
606 dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
607 return NULL;
610 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
611 for (i = 0; i < nwname; i++) {
612 size += 2 + strlen(wnames[i]); /* wname[s] */
615 fc = v9fs_create_common(bufp, size, TWALK);
616 if (IS_ERR(fc))
617 goto error;
619 v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
620 v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
621 v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
622 for (i = 0; i < nwname; i++) {
623 v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
626 if (buf_check_overflow(bufp)) {
627 kfree(fc);
628 fc = ERR_PTR(-ENOMEM);
630 error:
631 return fc;
634 struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
636 int size;
637 struct v9fs_fcall *fc;
638 struct cbuf buffer;
639 struct cbuf *bufp = &buffer;
641 size = 4 + 1; /* fid[4] mode[1] */
642 fc = v9fs_create_common(bufp, size, TOPEN);
643 if (IS_ERR(fc))
644 goto error;
646 v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
647 v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
649 if (buf_check_overflow(bufp)) {
650 kfree(fc);
651 fc = ERR_PTR(-ENOMEM);
653 error:
654 return fc;
657 struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode)
659 int size;
660 struct v9fs_fcall *fc;
661 struct cbuf buffer;
662 struct cbuf *bufp = &buffer;
664 size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */
665 fc = v9fs_create_common(bufp, size, TCREATE);
666 if (IS_ERR(fc))
667 goto error;
669 v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
670 v9fs_put_str(bufp, name, &fc->params.tcreate.name);
671 v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
672 v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
674 if (buf_check_overflow(bufp)) {
675 kfree(fc);
676 fc = ERR_PTR(-ENOMEM);
678 error:
679 return fc;
682 struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
684 int size;
685 struct v9fs_fcall *fc;
686 struct cbuf buffer;
687 struct cbuf *bufp = &buffer;
689 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
690 fc = v9fs_create_common(bufp, size, TREAD);
691 if (IS_ERR(fc))
692 goto error;
694 v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
695 v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
696 v9fs_put_int32(bufp, count, &fc->params.tread.count);
698 if (buf_check_overflow(bufp)) {
699 kfree(fc);
700 fc = ERR_PTR(-ENOMEM);
702 error:
703 return fc;
706 struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
707 const char __user * data)
709 int size, err;
710 struct v9fs_fcall *fc;
711 struct cbuf buffer;
712 struct cbuf *bufp = &buffer;
714 size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */
715 fc = v9fs_create_common(bufp, size, TWRITE);
716 if (IS_ERR(fc))
717 goto error;
719 v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
720 v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
721 v9fs_put_int32(bufp, count, &fc->params.twrite.count);
722 err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
723 if (err) {
724 kfree(fc);
725 fc = ERR_PTR(err);
728 if (buf_check_overflow(bufp)) {
729 kfree(fc);
730 fc = ERR_PTR(-ENOMEM);
732 error:
733 return fc;
736 struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
738 int size;
739 struct v9fs_fcall *fc;
740 struct cbuf buffer;
741 struct cbuf *bufp = &buffer;
743 size = 4; /* fid[4] */
744 fc = v9fs_create_common(bufp, size, TCLUNK);
745 if (IS_ERR(fc))
746 goto error;
748 v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
750 if (buf_check_overflow(bufp)) {
751 kfree(fc);
752 fc = ERR_PTR(-ENOMEM);
754 error:
755 return fc;
758 struct v9fs_fcall *v9fs_create_tremove(u32 fid)
760 int size;
761 struct v9fs_fcall *fc;
762 struct cbuf buffer;
763 struct cbuf *bufp = &buffer;
765 size = 4; /* fid[4] */
766 fc = v9fs_create_common(bufp, size, TREMOVE);
767 if (IS_ERR(fc))
768 goto error;
770 v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
772 if (buf_check_overflow(bufp)) {
773 kfree(fc);
774 fc = ERR_PTR(-ENOMEM);
776 error:
777 return fc;
780 struct v9fs_fcall *v9fs_create_tstat(u32 fid)
782 int size;
783 struct v9fs_fcall *fc;
784 struct cbuf buffer;
785 struct cbuf *bufp = &buffer;
787 size = 4; /* fid[4] */
788 fc = v9fs_create_common(bufp, size, TSTAT);
789 if (IS_ERR(fc))
790 goto error;
792 v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
794 if (buf_check_overflow(bufp)) {
795 kfree(fc);
796 fc = ERR_PTR(-ENOMEM);
798 error:
799 return fc;
802 struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
803 int extended)
805 int size, statsz;
806 struct v9fs_fcall *fc;
807 struct cbuf buffer;
808 struct cbuf *bufp = &buffer;
810 statsz = v9fs_size_wstat(wstat, extended);
811 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
812 fc = v9fs_create_common(bufp, size, TWSTAT);
813 if (IS_ERR(fc))
814 goto error;
816 v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
817 buf_put_int16(bufp, statsz + 2);
818 v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
820 if (buf_check_overflow(bufp)) {
821 kfree(fc);
822 fc = ERR_PTR(-ENOMEM);
824 error:
825 return fc;