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 version 2
12 * as published by the Free Software Foundation.
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.
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
27 #include <linux/module.h>
28 #include <linux/errno.h>
30 #include <linux/sched.h>
31 #include <linux/idr.h>
32 #include <linux/uaccess.h>
33 #include <net/9p/9p.h>
36 * Buffer to help with string parsing
44 static inline void buf_init(struct cbuf
*buf
, void *data
, int datalen
)
46 buf
->sp
= buf
->p
= data
;
47 buf
->ep
= data
+ datalen
;
50 static inline int buf_check_overflow(struct cbuf
*buf
)
52 return buf
->p
> buf
->ep
;
55 static int buf_check_size(struct cbuf
*buf
, int len
)
57 if (buf
->p
+ len
> buf
->ep
) {
58 if (buf
->p
< buf
->ep
) {
60 "buffer overflow: want %d has %d\n", len
,
61 (int)(buf
->ep
- buf
->p
));
72 static void *buf_alloc(struct cbuf
*buf
, int len
)
76 if (buf_check_size(buf
, len
)) {
84 static void buf_put_int8(struct cbuf
*buf
, u8 val
)
86 if (buf_check_size(buf
, 1)) {
92 static void buf_put_int16(struct cbuf
*buf
, u16 val
)
94 if (buf_check_size(buf
, 2)) {
95 *(__le16
*) buf
->p
= cpu_to_le16(val
);
100 static void buf_put_int32(struct cbuf
*buf
, u32 val
)
102 if (buf_check_size(buf
, 4)) {
103 *(__le32
*)buf
->p
= cpu_to_le32(val
);
108 static void buf_put_int64(struct cbuf
*buf
, u64 val
)
110 if (buf_check_size(buf
, 8)) {
111 *(__le64
*)buf
->p
= cpu_to_le64(val
);
116 static char *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
);
124 memcpy(buf
->p
, s
, slen
);
131 static u8
buf_get_int8(struct cbuf
*buf
)
135 if (buf_check_size(buf
, 1)) {
143 static u16
buf_get_int16(struct cbuf
*buf
)
147 if (buf_check_size(buf
, 2)) {
148 ret
= le16_to_cpu(*(__le16
*)buf
->p
);
155 static u32
buf_get_int32(struct cbuf
*buf
)
159 if (buf_check_size(buf
, 4)) {
160 ret
= le32_to_cpu(*(__le32
*)buf
->p
);
167 static u64
buf_get_int64(struct cbuf
*buf
)
171 if (buf_check_size(buf
, 8)) {
172 ret
= le64_to_cpu(*(__le64
*)buf
->p
);
179 static void buf_get_str(struct cbuf
*buf
, struct p9_str
*vstr
)
181 vstr
->len
= buf_get_int16(buf
);
182 if (!buf_check_overflow(buf
) && buf_check_size(buf
, vstr
->len
)) {
191 static void buf_get_qid(struct cbuf
*bufp
, struct p9_qid
*qid
)
193 qid
->type
= buf_get_int8(bufp
);
194 qid
->version
= buf_get_int32(bufp
);
195 qid
->path
= buf_get_int64(bufp
);
199 * p9_size_wstat - calculate the size of a variable length stat struct
200 * @wstat: metadata (stat) structure
201 * @dotu: non-zero if 9P2000.u
205 static int p9_size_wstat(struct p9_wstat
*wstat
, int dotu
)
210 P9_EPRINTK(KERN_ERR
, "p9_size_stat: got a NULL stat pointer\n");
214 size
= /* 2 + *//* size[2] */
217 1 + /* qid.type[1] */
218 4 + /* qid.vers[4] */
219 8 + /* qid.path[8] */
224 8; /* minimum sum of string lengths */
227 size
+= strlen(wstat
->name
);
229 size
+= strlen(wstat
->uid
);
231 size
+= strlen(wstat
->gid
);
233 size
+= strlen(wstat
->muid
);
236 size
+= 4 + /* n_uid[4] */
239 2; /* string length of extension[4] */
240 if (wstat
->extension
)
241 size
+= strlen(wstat
->extension
);
248 * buf_get_stat - safely decode a recieved metadata (stat) structure
249 * @bufp: buffer to deserialize
250 * @stat: metadata (stat) structure
251 * @dotu: non-zero if 9P2000.u
256 buf_get_stat(struct cbuf
*bufp
, struct p9_stat
*stat
, int dotu
)
258 stat
->size
= buf_get_int16(bufp
);
259 stat
->type
= buf_get_int16(bufp
);
260 stat
->dev
= buf_get_int32(bufp
);
261 stat
->qid
.type
= buf_get_int8(bufp
);
262 stat
->qid
.version
= buf_get_int32(bufp
);
263 stat
->qid
.path
= buf_get_int64(bufp
);
264 stat
->mode
= buf_get_int32(bufp
);
265 stat
->atime
= buf_get_int32(bufp
);
266 stat
->mtime
= buf_get_int32(bufp
);
267 stat
->length
= buf_get_int64(bufp
);
268 buf_get_str(bufp
, &stat
->name
);
269 buf_get_str(bufp
, &stat
->uid
);
270 buf_get_str(bufp
, &stat
->gid
);
271 buf_get_str(bufp
, &stat
->muid
);
274 buf_get_str(bufp
, &stat
->extension
);
275 stat
->n_uid
= buf_get_int32(bufp
);
276 stat
->n_gid
= buf_get_int32(bufp
);
277 stat
->n_muid
= buf_get_int32(bufp
);
282 * p9_deserialize_stat - decode a received metadata structure
283 * @buf: buffer to deserialize
284 * @buflen: length of received buffer
285 * @stat: metadata structure to decode into
286 * @dotu: non-zero if 9P2000.u
288 * Note: stat will point to the buf region.
292 p9_deserialize_stat(void *buf
, u32 buflen
, struct p9_stat
*stat
,
296 struct cbuf
*bufp
= &buffer
;
299 buf_init(bufp
, buf
, buflen
);
301 buf_get_stat(bufp
, stat
, dotu
);
303 if (buf_check_overflow(bufp
))
308 EXPORT_SYMBOL(p9_deserialize_stat
);
311 * deserialize_fcall - unmarshal a response
312 * @buf: recieved buffer
313 * @buflen: length of received buffer
314 * @rcall: fcall structure to populate
315 * @rcalllen: length of fcall structure to populate
316 * @dotu: non-zero if 9P2000.u
321 p9_deserialize_fcall(void *buf
, u32 buflen
, struct p9_fcall
*rcall
,
326 struct cbuf
*bufp
= &buffer
;
329 buf_init(bufp
, buf
, buflen
);
331 rcall
->size
= buf_get_int32(bufp
);
332 rcall
->id
= buf_get_int8(bufp
);
333 rcall
->tag
= buf_get_int16(bufp
);
335 P9_DPRINTK(P9_DEBUG_CONV
, "size %d id %d tag %d\n", rcall
->size
,
336 rcall
->id
, rcall
->tag
);
340 P9_EPRINTK(KERN_ERR
, "unknown message type: %d\n", rcall
->id
);
343 rcall
->params
.rversion
.msize
= buf_get_int32(bufp
);
344 buf_get_str(bufp
, &rcall
->params
.rversion
.version
);
349 rcall
->params
.rattach
.qid
.type
= buf_get_int8(bufp
);
350 rcall
->params
.rattach
.qid
.version
= buf_get_int32(bufp
);
351 rcall
->params
.rattach
.qid
.path
= buf_get_int64(bufp
);
354 rcall
->params
.rwalk
.nwqid
= buf_get_int16(bufp
);
355 if (rcall
->params
.rwalk
.nwqid
> P9_MAXWELEM
) {
357 "Rwalk with more than %d qids: %d\n",
358 P9_MAXWELEM
, rcall
->params
.rwalk
.nwqid
);
362 for (i
= 0; i
< rcall
->params
.rwalk
.nwqid
; i
++)
363 buf_get_qid(bufp
, &rcall
->params
.rwalk
.wqids
[i
]);
366 buf_get_qid(bufp
, &rcall
->params
.ropen
.qid
);
367 rcall
->params
.ropen
.iounit
= buf_get_int32(bufp
);
370 buf_get_qid(bufp
, &rcall
->params
.rcreate
.qid
);
371 rcall
->params
.rcreate
.iounit
= buf_get_int32(bufp
);
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
);
379 rcall
->params
.rwrite
.count
= buf_get_int32(bufp
);
387 buf_get_stat(bufp
, &rcall
->params
.rstat
.stat
, dotu
);
392 buf_get_str(bufp
, &rcall
->params
.rerror
.error
);
394 rcall
->params
.rerror
.errno
= buf_get_int16(bufp
);
398 if (buf_check_overflow(bufp
)) {
399 P9_DPRINTK(P9_DEBUG_ERROR
, "buffer overflow\n");
403 return bufp
->p
- bufp
->sp
;
405 EXPORT_SYMBOL(p9_deserialize_fcall
);
407 static inline void p9_put_int8(struct cbuf
*bufp
, u8 val
, u8
* p
)
410 buf_put_int8(bufp
, val
);
413 static inline void p9_put_int16(struct cbuf
*bufp
, u16 val
, u16
* p
)
416 buf_put_int16(bufp
, val
);
419 static inline void p9_put_int32(struct cbuf
*bufp
, u32 val
, u32
* p
)
422 buf_put_int32(bufp
, val
);
425 static inline void p9_put_int64(struct cbuf
*bufp
, u64 val
, u64
* p
)
428 buf_put_int64(bufp
, val
);
432 p9_put_str(struct cbuf
*bufp
, char *data
, struct p9_str
*str
)
442 s
= buf_put_stringn(bufp
, data
, len
);
450 p9_put_data(struct cbuf
*bufp
, const char *data
, int count
,
451 unsigned char **pdata
)
453 *pdata
= buf_alloc(bufp
, count
);
456 memmove(*pdata
, data
, count
);
461 p9_put_user_data(struct cbuf
*bufp
, const char __user
*data
, int count
,
462 unsigned char **pdata
)
464 *pdata
= buf_alloc(bufp
, count
);
467 return copy_from_user(*pdata
, data
, count
);
471 p9_put_wstat(struct cbuf
*bufp
, struct p9_wstat
*wstat
,
472 struct p9_stat
*stat
, int statsz
, int dotu
)
474 p9_put_int16(bufp
, statsz
, &stat
->size
);
475 p9_put_int16(bufp
, wstat
->type
, &stat
->type
);
476 p9_put_int32(bufp
, wstat
->dev
, &stat
->dev
);
477 p9_put_int8(bufp
, wstat
->qid
.type
, &stat
->qid
.type
);
478 p9_put_int32(bufp
, wstat
->qid
.version
, &stat
->qid
.version
);
479 p9_put_int64(bufp
, wstat
->qid
.path
, &stat
->qid
.path
);
480 p9_put_int32(bufp
, wstat
->mode
, &stat
->mode
);
481 p9_put_int32(bufp
, wstat
->atime
, &stat
->atime
);
482 p9_put_int32(bufp
, wstat
->mtime
, &stat
->mtime
);
483 p9_put_int64(bufp
, wstat
->length
, &stat
->length
);
485 p9_put_str(bufp
, wstat
->name
, &stat
->name
);
486 p9_put_str(bufp
, wstat
->uid
, &stat
->uid
);
487 p9_put_str(bufp
, wstat
->gid
, &stat
->gid
);
488 p9_put_str(bufp
, wstat
->muid
, &stat
->muid
);
491 p9_put_str(bufp
, wstat
->extension
, &stat
->extension
);
492 p9_put_int32(bufp
, wstat
->n_uid
, &stat
->n_uid
);
493 p9_put_int32(bufp
, wstat
->n_gid
, &stat
->n_gid
);
494 p9_put_int32(bufp
, wstat
->n_muid
, &stat
->n_muid
);
498 static struct p9_fcall
*
499 p9_create_common(struct cbuf
*bufp
, u32 size
, u8 id
)
503 size
+= 4 + 1 + 2; /* size[4] id[1] tag[2] */
504 fc
= kmalloc(sizeof(struct p9_fcall
) + size
, GFP_KERNEL
);
506 return ERR_PTR(-ENOMEM
);
508 fc
->sdata
= (char *)fc
+ sizeof(*fc
);
510 buf_init(bufp
, (char *)fc
->sdata
, size
);
511 p9_put_int32(bufp
, size
, &fc
->size
);
512 p9_put_int8(bufp
, id
, &fc
->id
);
513 p9_put_int16(bufp
, P9_NOTAG
, &fc
->tag
);
519 * p9_set_tag - set the tag field of an &p9_fcall structure
520 * @fc: fcall structure to set tag within
521 * @tag: tag id to set
524 void p9_set_tag(struct p9_fcall
*fc
, u16 tag
)
527 *(__le16
*) (fc
->sdata
+ 5) = cpu_to_le16(tag
);
529 EXPORT_SYMBOL(p9_set_tag
);
532 * p9_create_tversion - allocates and creates a T_VERSION request
533 * @msize: requested maximum data size
534 * @version: version string to negotiate
537 struct p9_fcall
*p9_create_tversion(u32 msize
, char *version
)
542 struct cbuf
*bufp
= &buffer
;
544 size
= 4 + 2 + strlen(version
); /* msize[4] version[s] */
545 fc
= p9_create_common(bufp
, size
, P9_TVERSION
);
549 p9_put_int32(bufp
, msize
, &fc
->params
.tversion
.msize
);
550 p9_put_str(bufp
, version
, &fc
->params
.tversion
.version
);
552 if (buf_check_overflow(bufp
)) {
554 fc
= ERR_PTR(-ENOMEM
);
559 EXPORT_SYMBOL(p9_create_tversion
);
562 * p9_create_tauth - allocates and creates a T_AUTH request
563 * @afid: handle to use for authentication protocol
564 * @uname: user name attempting to authenticate
565 * @aname: mount specifier for remote server
566 * @n_uname: numeric id for user attempting to authneticate
567 * @dotu: 9P2000.u extension flag
571 struct p9_fcall
*p9_create_tauth(u32 afid
, char *uname
, char *aname
,
572 u32 n_uname
, int dotu
)
577 struct cbuf
*bufp
= &buffer
;
579 /* afid[4] uname[s] aname[s] */
582 size
+= strlen(uname
);
585 size
+= strlen(aname
);
588 size
+= 4; /* n_uname */
590 fc
= p9_create_common(bufp
, size
, P9_TAUTH
);
594 p9_put_int32(bufp
, afid
, &fc
->params
.tauth
.afid
);
595 p9_put_str(bufp
, uname
, &fc
->params
.tauth
.uname
);
596 p9_put_str(bufp
, aname
, &fc
->params
.tauth
.aname
);
598 p9_put_int32(bufp
, n_uname
, &fc
->params
.tauth
.n_uname
);
600 if (buf_check_overflow(bufp
)) {
602 fc
= ERR_PTR(-ENOMEM
);
607 EXPORT_SYMBOL(p9_create_tauth
);
610 * p9_create_tattach - allocates and creates a T_ATTACH request
611 * @fid: handle to use for the new mount point
612 * @afid: handle to use for authentication protocol
613 * @uname: user name attempting to attach
614 * @aname: mount specifier for remote server
615 * @n_uname: numeric id for user attempting to attach
616 * @n_uname: numeric id for user attempting to attach
617 * @dotu: 9P2000.u extension flag
622 p9_create_tattach(u32 fid
, u32 afid
, char *uname
, char *aname
,
623 u32 n_uname
, int dotu
)
628 struct cbuf
*bufp
= &buffer
;
630 /* fid[4] afid[4] uname[s] aname[s] */
631 size
= 4 + 4 + 2 + 2;
633 size
+= strlen(uname
);
636 size
+= strlen(aname
);
639 size
+= 4; /* n_uname */
641 fc
= p9_create_common(bufp
, size
, P9_TATTACH
);
645 p9_put_int32(bufp
, fid
, &fc
->params
.tattach
.fid
);
646 p9_put_int32(bufp
, afid
, &fc
->params
.tattach
.afid
);
647 p9_put_str(bufp
, uname
, &fc
->params
.tattach
.uname
);
648 p9_put_str(bufp
, aname
, &fc
->params
.tattach
.aname
);
650 p9_put_int32(bufp
, n_uname
, &fc
->params
.tattach
.n_uname
);
655 EXPORT_SYMBOL(p9_create_tattach
);
658 * p9_create_tflush - allocates and creates a T_FLUSH request
659 * @oldtag: tag id for the transaction we are attempting to cancel
663 struct p9_fcall
*p9_create_tflush(u16 oldtag
)
668 struct cbuf
*bufp
= &buffer
;
670 size
= 2; /* oldtag[2] */
671 fc
= p9_create_common(bufp
, size
, P9_TFLUSH
);
675 p9_put_int16(bufp
, oldtag
, &fc
->params
.tflush
.oldtag
);
677 if (buf_check_overflow(bufp
)) {
679 fc
= ERR_PTR(-ENOMEM
);
684 EXPORT_SYMBOL(p9_create_tflush
);
687 * p9_create_twalk - allocates and creates a T_FLUSH request
688 * @fid: handle we are traversing from
689 * @newfid: a new handle for this transaction
690 * @nwname: number of path elements to traverse
691 * @wnames: array of path elements
695 struct p9_fcall
*p9_create_twalk(u32 fid
, u32 newfid
, u16 nwname
,
701 struct cbuf
*bufp
= &buffer
;
703 if (nwname
> P9_MAXWELEM
) {
704 P9_DPRINTK(P9_DEBUG_ERROR
, "nwname > %d\n", P9_MAXWELEM
);
708 size
= 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
709 for (i
= 0; i
< nwname
; i
++) {
710 size
+= 2 + strlen(wnames
[i
]); /* wname[s] */
713 fc
= p9_create_common(bufp
, size
, P9_TWALK
);
717 p9_put_int32(bufp
, fid
, &fc
->params
.twalk
.fid
);
718 p9_put_int32(bufp
, newfid
, &fc
->params
.twalk
.newfid
);
719 p9_put_int16(bufp
, nwname
, &fc
->params
.twalk
.nwname
);
720 for (i
= 0; i
< nwname
; i
++) {
721 p9_put_str(bufp
, wnames
[i
], &fc
->params
.twalk
.wnames
[i
]);
724 if (buf_check_overflow(bufp
)) {
726 fc
= ERR_PTR(-ENOMEM
);
731 EXPORT_SYMBOL(p9_create_twalk
);
734 * p9_create_topen - allocates and creates a T_OPEN request
735 * @fid: handle we are trying to open
736 * @mode: what mode we are trying to open the file in
740 struct p9_fcall
*p9_create_topen(u32 fid
, u8 mode
)
745 struct cbuf
*bufp
= &buffer
;
747 size
= 4 + 1; /* fid[4] mode[1] */
748 fc
= p9_create_common(bufp
, size
, P9_TOPEN
);
752 p9_put_int32(bufp
, fid
, &fc
->params
.topen
.fid
);
753 p9_put_int8(bufp
, mode
, &fc
->params
.topen
.mode
);
755 if (buf_check_overflow(bufp
)) {
757 fc
= ERR_PTR(-ENOMEM
);
762 EXPORT_SYMBOL(p9_create_topen
);
765 * p9_create_tcreate - allocates and creates a T_CREATE request
766 * @fid: handle of directory we are trying to create in
767 * @name: name of the file we are trying to create
768 * @perm: permissions for the file we are trying to create
769 * @mode: what mode we are trying to open the file in
770 * @extension: 9p2000.u extension string (for special files)
771 * @dotu: 9p2000.u enabled flag
773 * Note: Plan 9 create semantics include opening the resulting file
774 * which is why mode is included.
777 struct p9_fcall
*p9_create_tcreate(u32 fid
, char *name
, u32 perm
, u8 mode
,
778 char *extension
, int dotu
)
783 struct cbuf
*bufp
= &buffer
;
785 /* fid[4] name[s] perm[4] mode[1] */
786 size
= 4 + 2 + strlen(name
) + 4 + 1;
788 size
+= 2 + /* extension[s] */
789 (extension
== NULL
? 0 : strlen(extension
));
792 fc
= p9_create_common(bufp
, size
, P9_TCREATE
);
796 p9_put_int32(bufp
, fid
, &fc
->params
.tcreate
.fid
);
797 p9_put_str(bufp
, name
, &fc
->params
.tcreate
.name
);
798 p9_put_int32(bufp
, perm
, &fc
->params
.tcreate
.perm
);
799 p9_put_int8(bufp
, mode
, &fc
->params
.tcreate
.mode
);
801 p9_put_str(bufp
, extension
, &fc
->params
.tcreate
.extension
);
803 if (buf_check_overflow(bufp
)) {
805 fc
= ERR_PTR(-ENOMEM
);
810 EXPORT_SYMBOL(p9_create_tcreate
);
813 * p9_create_tread - allocates and creates a T_READ request
814 * @fid: handle of the file we are trying to read
815 * @offset: offset to start reading from
816 * @count: how many bytes to read
819 struct p9_fcall
*p9_create_tread(u32 fid
, u64 offset
, u32 count
)
824 struct cbuf
*bufp
= &buffer
;
826 size
= 4 + 8 + 4; /* fid[4] offset[8] count[4] */
827 fc
= p9_create_common(bufp
, size
, P9_TREAD
);
831 p9_put_int32(bufp
, fid
, &fc
->params
.tread
.fid
);
832 p9_put_int64(bufp
, offset
, &fc
->params
.tread
.offset
);
833 p9_put_int32(bufp
, count
, &fc
->params
.tread
.count
);
835 if (buf_check_overflow(bufp
)) {
837 fc
= ERR_PTR(-ENOMEM
);
842 EXPORT_SYMBOL(p9_create_tread
);
845 * p9_create_twrite - allocates and creates a T_WRITE request from the kernel
846 * @fid: handle of the file we are trying to write
847 * @offset: offset to start writing at
848 * @count: how many bytes to write
849 * @data: data to write
851 * This function will create a requst with data buffers from the kernel
852 * such as the page cache.
855 struct p9_fcall
*p9_create_twrite(u32 fid
, u64 offset
, u32 count
,
861 struct cbuf
*bufp
= &buffer
;
863 /* fid[4] offset[8] count[4] data[count] */
864 size
= 4 + 8 + 4 + count
;
865 fc
= p9_create_common(bufp
, size
, P9_TWRITE
);
869 p9_put_int32(bufp
, fid
, &fc
->params
.twrite
.fid
);
870 p9_put_int64(bufp
, offset
, &fc
->params
.twrite
.offset
);
871 p9_put_int32(bufp
, count
, &fc
->params
.twrite
.count
);
872 err
= p9_put_data(bufp
, data
, count
, &fc
->params
.twrite
.data
);
879 if (buf_check_overflow(bufp
)) {
881 fc
= ERR_PTR(-ENOMEM
);
886 EXPORT_SYMBOL(p9_create_twrite
);
889 * p9_create_twrite_u - allocates and creates a T_WRITE request from userspace
890 * @fid: handle of the file we are trying to write
891 * @offset: offset to start writing at
892 * @count: how many bytes to write
893 * @data: data to write
895 * This function will create a request with data buffers from userspace
898 struct p9_fcall
*p9_create_twrite_u(u32 fid
, u64 offset
, u32 count
,
899 const char __user
*data
)
904 struct cbuf
*bufp
= &buffer
;
906 /* fid[4] offset[8] count[4] data[count] */
907 size
= 4 + 8 + 4 + count
;
908 fc
= p9_create_common(bufp
, size
, P9_TWRITE
);
912 p9_put_int32(bufp
, fid
, &fc
->params
.twrite
.fid
);
913 p9_put_int64(bufp
, offset
, &fc
->params
.twrite
.offset
);
914 p9_put_int32(bufp
, count
, &fc
->params
.twrite
.count
);
915 err
= p9_put_user_data(bufp
, data
, count
, &fc
->params
.twrite
.data
);
922 if (buf_check_overflow(bufp
)) {
924 fc
= ERR_PTR(-ENOMEM
);
929 EXPORT_SYMBOL(p9_create_twrite_u
);
932 * p9_create_tclunk - allocate a request to forget about a file handle
933 * @fid: handle of the file we closing or forgetting about
935 * clunk is used both to close open files and to discard transient handles
936 * which may be created during meta-data operations and hierarchy traversal.
939 struct p9_fcall
*p9_create_tclunk(u32 fid
)
944 struct cbuf
*bufp
= &buffer
;
946 size
= 4; /* fid[4] */
947 fc
= p9_create_common(bufp
, size
, P9_TCLUNK
);
951 p9_put_int32(bufp
, fid
, &fc
->params
.tclunk
.fid
);
953 if (buf_check_overflow(bufp
)) {
955 fc
= ERR_PTR(-ENOMEM
);
960 EXPORT_SYMBOL(p9_create_tclunk
);
963 * p9_create_tremove - allocate and create a request to remove a file
964 * @fid: handle of the file or directory we are removing
968 struct p9_fcall
*p9_create_tremove(u32 fid
)
973 struct cbuf
*bufp
= &buffer
;
975 size
= 4; /* fid[4] */
976 fc
= p9_create_common(bufp
, size
, P9_TREMOVE
);
980 p9_put_int32(bufp
, fid
, &fc
->params
.tremove
.fid
);
982 if (buf_check_overflow(bufp
)) {
984 fc
= ERR_PTR(-ENOMEM
);
989 EXPORT_SYMBOL(p9_create_tremove
);
992 * p9_create_tstat - allocate and populate a request for attributes
993 * @fid: handle of the file or directory we are trying to get the attributes of
997 struct p9_fcall
*p9_create_tstat(u32 fid
)
1000 struct p9_fcall
*fc
;
1002 struct cbuf
*bufp
= &buffer
;
1004 size
= 4; /* fid[4] */
1005 fc
= p9_create_common(bufp
, size
, P9_TSTAT
);
1009 p9_put_int32(bufp
, fid
, &fc
->params
.tstat
.fid
);
1011 if (buf_check_overflow(bufp
)) {
1013 fc
= ERR_PTR(-ENOMEM
);
1018 EXPORT_SYMBOL(p9_create_tstat
);
1021 * p9_create_tstat - allocate and populate a request to change attributes
1022 * @fid: handle of the file or directory we are trying to change
1023 * @wstat: &p9_stat structure with attributes we wish to set
1024 * @dotu: 9p2000.u enabled flag
1028 struct p9_fcall
*p9_create_twstat(u32 fid
, struct p9_wstat
*wstat
,
1032 struct p9_fcall
*fc
;
1034 struct cbuf
*bufp
= &buffer
;
1036 statsz
= p9_size_wstat(wstat
, dotu
);
1037 size
= 4 + 2 + 2 + statsz
; /* fid[4] stat[n] */
1038 fc
= p9_create_common(bufp
, size
, P9_TWSTAT
);
1042 p9_put_int32(bufp
, fid
, &fc
->params
.twstat
.fid
);
1043 buf_put_int16(bufp
, statsz
+ 2);
1044 p9_put_wstat(bufp
, wstat
, &fc
->params
.twstat
.stat
, statsz
, dotu
);
1046 if (buf_check_overflow(bufp
)) {
1048 fc
= ERR_PTR(-ENOMEM
);
1053 EXPORT_SYMBOL(p9_create_twstat
);