xref: /openbmc/linux/net/9p/protocol.c (revision 3e7759b94a0fcfdd6771caa64a37dda7ce825874)
11f327613SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ace51c4dSEric Van Hensbergen /*
3ace51c4dSEric Van Hensbergen  * 9P Protocol Support Code
4ace51c4dSEric Van Hensbergen  *
5ace51c4dSEric Van Hensbergen  *  Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
6ace51c4dSEric Van Hensbergen  *
7ace51c4dSEric Van Hensbergen  *  Base on code from Anthony Liguori <aliguori@us.ibm.com>
8ace51c4dSEric Van Hensbergen  *  Copyright (C) 2008 by IBM, Corp.
9ace51c4dSEric Van Hensbergen  */
10ace51c4dSEric Van Hensbergen 
11ace51c4dSEric Van Hensbergen #include <linux/module.h>
12ace51c4dSEric Van Hensbergen #include <linux/errno.h>
1301b0c5cfSThiago Farina #include <linux/kernel.h>
1451a87c55SEric Van Hensbergen #include <linux/uaccess.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
16e7f4b8f1SEric Van Hensbergen #include <linux/sched.h>
1701b0c5cfSThiago Farina #include <linux/stddef.h>
18beeebc92SEric Van Hensbergen #include <linux/types.h>
194f3b35c1SAl Viro #include <linux/uio.h>
20ace51c4dSEric Van Hensbergen #include <net/9p/9p.h>
21ace51c4dSEric Van Hensbergen #include <net/9p/client.h>
22ace51c4dSEric Van Hensbergen #include "protocol.h"
23ace51c4dSEric Van Hensbergen 
24348b5901SAneesh Kumar K.V #include <trace/events/9p.h>
25348b5901SAneesh Kumar K.V 
261effdbf9SChristian Schoenebeck /* len[2] text[len] */
271effdbf9SChristian Schoenebeck #define P9_STRLEN(s) \
281effdbf9SChristian Schoenebeck 	(2 + min_t(size_t, s ? strlen(s) : 0, USHRT_MAX))
291effdbf9SChristian Schoenebeck 
301effdbf9SChristian Schoenebeck /**
311effdbf9SChristian Schoenebeck  * p9_msg_buf_size - Returns a buffer size sufficiently large to hold the
321effdbf9SChristian Schoenebeck  * intended 9p message.
331effdbf9SChristian Schoenebeck  * @c: client
341effdbf9SChristian Schoenebeck  * @type: message type
351effdbf9SChristian Schoenebeck  * @fmt: format template for assembling request message
361effdbf9SChristian Schoenebeck  * (see p9pdu_vwritef)
371effdbf9SChristian Schoenebeck  * @ap: variable arguments to be fed to passed format template
381effdbf9SChristian Schoenebeck  * (see p9pdu_vwritef)
391effdbf9SChristian Schoenebeck  *
401effdbf9SChristian Schoenebeck  * Note: Even for response types (P9_R*) the format template and variable
411effdbf9SChristian Schoenebeck  * arguments must always be for the originating request type (P9_T*).
421effdbf9SChristian Schoenebeck  */
p9_msg_buf_size(struct p9_client * c,enum p9_msg_t type,const char * fmt,va_list ap)431effdbf9SChristian Schoenebeck size_t p9_msg_buf_size(struct p9_client *c, enum p9_msg_t type,
441effdbf9SChristian Schoenebeck 			const char *fmt, va_list ap)
451effdbf9SChristian Schoenebeck {
461effdbf9SChristian Schoenebeck 	/* size[4] type[1] tag[2] */
471effdbf9SChristian Schoenebeck 	const int hdr = 4 + 1 + 2;
481effdbf9SChristian Schoenebeck 	/* ename[s] errno[4] */
491effdbf9SChristian Schoenebeck 	const int rerror_size = hdr + P9_ERRMAX + 4;
501effdbf9SChristian Schoenebeck 	/* ecode[4] */
511effdbf9SChristian Schoenebeck 	const int rlerror_size = hdr + 4;
521effdbf9SChristian Schoenebeck 	const int err_size =
531effdbf9SChristian Schoenebeck 		c->proto_version == p9_proto_2000L ? rlerror_size : rerror_size;
541effdbf9SChristian Schoenebeck 
551effdbf9SChristian Schoenebeck 	static_assert(NAME_MAX <= 4*1024, "p9_msg_buf_size() currently assumes "
561effdbf9SChristian Schoenebeck 				  "a max. allowed directory entry name length of 4k");
571effdbf9SChristian Schoenebeck 
581effdbf9SChristian Schoenebeck 	switch (type) {
591effdbf9SChristian Schoenebeck 
601effdbf9SChristian Schoenebeck 	/* message types not used at all */
611effdbf9SChristian Schoenebeck 	case P9_TERROR:
621effdbf9SChristian Schoenebeck 	case P9_TLERROR:
631effdbf9SChristian Schoenebeck 	case P9_TAUTH:
641effdbf9SChristian Schoenebeck 	case P9_RAUTH:
651effdbf9SChristian Schoenebeck 		BUG();
661effdbf9SChristian Schoenebeck 
671effdbf9SChristian Schoenebeck 	/* variable length & potentially large message types */
681effdbf9SChristian Schoenebeck 	case P9_TATTACH:
691effdbf9SChristian Schoenebeck 		BUG_ON(strcmp("ddss?u", fmt));
701effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
711effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
721effdbf9SChristian Schoenebeck 		{
731effdbf9SChristian Schoenebeck 			const char *uname = va_arg(ap, const char *);
741effdbf9SChristian Schoenebeck 			const char *aname = va_arg(ap, const char *);
751effdbf9SChristian Schoenebeck 			/* fid[4] afid[4] uname[s] aname[s] n_uname[4] */
761effdbf9SChristian Schoenebeck 			return hdr + 4 + 4 + P9_STRLEN(uname) + P9_STRLEN(aname) + 4;
771effdbf9SChristian Schoenebeck 		}
781effdbf9SChristian Schoenebeck 	case P9_TWALK:
791effdbf9SChristian Schoenebeck 		BUG_ON(strcmp("ddT", fmt));
801effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
811effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
821effdbf9SChristian Schoenebeck 		{
831effdbf9SChristian Schoenebeck 			uint i, nwname = va_arg(ap, int);
841effdbf9SChristian Schoenebeck 			size_t wname_all;
851effdbf9SChristian Schoenebeck 			const char **wnames = va_arg(ap, const char **);
861effdbf9SChristian Schoenebeck 			for (i = 0, wname_all = 0; i < nwname; ++i) {
871effdbf9SChristian Schoenebeck 				wname_all += P9_STRLEN(wnames[i]);
881effdbf9SChristian Schoenebeck 			}
891effdbf9SChristian Schoenebeck 			/* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
901effdbf9SChristian Schoenebeck 			return hdr + 4 + 4 + 2 + wname_all;
911effdbf9SChristian Schoenebeck 		}
921effdbf9SChristian Schoenebeck 	case P9_RWALK:
931effdbf9SChristian Schoenebeck 		BUG_ON(strcmp("ddT", fmt));
941effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
951effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
961effdbf9SChristian Schoenebeck 		{
971effdbf9SChristian Schoenebeck 			uint nwname = va_arg(ap, int);
981effdbf9SChristian Schoenebeck 			/* nwqid[2] nwqid*(wqid[13]) */
991effdbf9SChristian Schoenebeck 			return max_t(size_t, hdr + 2 + nwname * 13, err_size);
1001effdbf9SChristian Schoenebeck 		}
1011effdbf9SChristian Schoenebeck 	case P9_TCREATE:
1021effdbf9SChristian Schoenebeck 		BUG_ON(strcmp("dsdb?s", fmt));
1031effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
1041effdbf9SChristian Schoenebeck 		{
1051effdbf9SChristian Schoenebeck 			const char *name = va_arg(ap, const char *);
1061effdbf9SChristian Schoenebeck 			if (c->proto_version == p9_proto_legacy) {
1071effdbf9SChristian Schoenebeck 				/* fid[4] name[s] perm[4] mode[1] */
1081effdbf9SChristian Schoenebeck 				return hdr + 4 + P9_STRLEN(name) + 4 + 1;
1091effdbf9SChristian Schoenebeck 			} else {
1101effdbf9SChristian Schoenebeck 				va_arg(ap, int32_t);
1111effdbf9SChristian Schoenebeck 				va_arg(ap, int);
1121effdbf9SChristian Schoenebeck 				{
1131effdbf9SChristian Schoenebeck 					const char *ext = va_arg(ap, const char *);
1141effdbf9SChristian Schoenebeck 					/* fid[4] name[s] perm[4] mode[1] extension[s] */
1151effdbf9SChristian Schoenebeck 					return hdr + 4 + P9_STRLEN(name) + 4 + 1 + P9_STRLEN(ext);
1161effdbf9SChristian Schoenebeck 				}
1171effdbf9SChristian Schoenebeck 			}
1181effdbf9SChristian Schoenebeck 		}
1191effdbf9SChristian Schoenebeck 	case P9_TLCREATE:
1201effdbf9SChristian Schoenebeck 		BUG_ON(strcmp("dsddg", fmt));
1211effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
1221effdbf9SChristian Schoenebeck 		{
1231effdbf9SChristian Schoenebeck 			const char *name = va_arg(ap, const char *);
1241effdbf9SChristian Schoenebeck 			/* fid[4] name[s] flags[4] mode[4] gid[4] */
1251effdbf9SChristian Schoenebeck 			return hdr + 4 + P9_STRLEN(name) + 4 + 4 + 4;
1261effdbf9SChristian Schoenebeck 		}
1271effdbf9SChristian Schoenebeck 	case P9_RREAD:
1281effdbf9SChristian Schoenebeck 	case P9_RREADDIR:
1291effdbf9SChristian Schoenebeck 		BUG_ON(strcmp("dqd", fmt));
1301effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
1311effdbf9SChristian Schoenebeck 		va_arg(ap, int64_t);
1321effdbf9SChristian Schoenebeck 		{
1331effdbf9SChristian Schoenebeck 			const int32_t count = va_arg(ap, int32_t);
1341effdbf9SChristian Schoenebeck 			/* count[4] data[count] */
1351effdbf9SChristian Schoenebeck 			return max_t(size_t, hdr + 4 + count, err_size);
1361effdbf9SChristian Schoenebeck 		}
1371effdbf9SChristian Schoenebeck 	case P9_TWRITE:
1381effdbf9SChristian Schoenebeck 		BUG_ON(strcmp("dqV", fmt));
1391effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
1401effdbf9SChristian Schoenebeck 		va_arg(ap, int64_t);
1411effdbf9SChristian Schoenebeck 		{
1421effdbf9SChristian Schoenebeck 			const int32_t count = va_arg(ap, int32_t);
1431effdbf9SChristian Schoenebeck 			/* fid[4] offset[8] count[4] data[count] */
1441effdbf9SChristian Schoenebeck 			return hdr + 4 + 8 + 4 + count;
1451effdbf9SChristian Schoenebeck 		}
1461effdbf9SChristian Schoenebeck 	case P9_TRENAMEAT:
1471effdbf9SChristian Schoenebeck 		BUG_ON(strcmp("dsds", fmt));
1481effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
1491effdbf9SChristian Schoenebeck 		{
1501effdbf9SChristian Schoenebeck 			const char *oldname, *newname;
1511effdbf9SChristian Schoenebeck 			oldname = va_arg(ap, const char *);
1521effdbf9SChristian Schoenebeck 			va_arg(ap, int32_t);
1531effdbf9SChristian Schoenebeck 			newname = va_arg(ap, const char *);
1541effdbf9SChristian Schoenebeck 			/* olddirfid[4] oldname[s] newdirfid[4] newname[s] */
1551effdbf9SChristian Schoenebeck 			return hdr + 4 + P9_STRLEN(oldname) + 4 + P9_STRLEN(newname);
1561effdbf9SChristian Schoenebeck 		}
1571effdbf9SChristian Schoenebeck 	case P9_TSYMLINK:
1581effdbf9SChristian Schoenebeck 		BUG_ON(strcmp("dssg", fmt));
1591effdbf9SChristian Schoenebeck 		va_arg(ap, int32_t);
1601effdbf9SChristian Schoenebeck 		{
1611effdbf9SChristian Schoenebeck 			const char *name = va_arg(ap, const char *);
1621effdbf9SChristian Schoenebeck 			const char *symtgt = va_arg(ap, const char *);
1631effdbf9SChristian Schoenebeck 			/* fid[4] name[s] symtgt[s] gid[4] */
1641effdbf9SChristian Schoenebeck 			return hdr + 4 + P9_STRLEN(name) + P9_STRLEN(symtgt) + 4;
1651effdbf9SChristian Schoenebeck 		}
1661effdbf9SChristian Schoenebeck 
1671effdbf9SChristian Schoenebeck 	case P9_RERROR:
1681effdbf9SChristian Schoenebeck 		return rerror_size;
1691effdbf9SChristian Schoenebeck 	case P9_RLERROR:
1701effdbf9SChristian Schoenebeck 		return rlerror_size;
1711effdbf9SChristian Schoenebeck 
1721effdbf9SChristian Schoenebeck 	/* small message types */
1731effdbf9SChristian Schoenebeck 	case P9_TWSTAT:
1741effdbf9SChristian Schoenebeck 	case P9_RSTAT:
1751effdbf9SChristian Schoenebeck 	case P9_RREADLINK:
1761effdbf9SChristian Schoenebeck 	case P9_TXATTRWALK:
1771effdbf9SChristian Schoenebeck 	case P9_TXATTRCREATE:
1781effdbf9SChristian Schoenebeck 	case P9_TLINK:
1791effdbf9SChristian Schoenebeck 	case P9_TMKDIR:
1801effdbf9SChristian Schoenebeck 	case P9_TMKNOD:
1811effdbf9SChristian Schoenebeck 	case P9_TRENAME:
1821effdbf9SChristian Schoenebeck 	case P9_TUNLINKAT:
1831effdbf9SChristian Schoenebeck 	case P9_TLOCK:
1841effdbf9SChristian Schoenebeck 		return 8 * 1024;
1851effdbf9SChristian Schoenebeck 
1861effdbf9SChristian Schoenebeck 	/* tiny message types */
1871effdbf9SChristian Schoenebeck 	default:
1881effdbf9SChristian Schoenebeck 		return 4 * 1024;
1891effdbf9SChristian Schoenebeck 
1901effdbf9SChristian Schoenebeck 	}
1911effdbf9SChristian Schoenebeck }
1921effdbf9SChristian Schoenebeck 
193ace51c4dSEric Van Hensbergen static int
194342fee1dSSripathi Kodi p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
195ace51c4dSEric Van Hensbergen 
p9stat_free(struct p9_wstat * stbuf)196ace51c4dSEric Van Hensbergen void p9stat_free(struct p9_wstat *stbuf)
197ace51c4dSEric Van Hensbergen {
198ace51c4dSEric Van Hensbergen 	kfree(stbuf->name);
19962e39417SDominique Martinet 	stbuf->name = NULL;
200ace51c4dSEric Van Hensbergen 	kfree(stbuf->uid);
20162e39417SDominique Martinet 	stbuf->uid = NULL;
202ace51c4dSEric Van Hensbergen 	kfree(stbuf->gid);
20362e39417SDominique Martinet 	stbuf->gid = NULL;
204ace51c4dSEric Van Hensbergen 	kfree(stbuf->muid);
20562e39417SDominique Martinet 	stbuf->muid = NULL;
206ace51c4dSEric Van Hensbergen 	kfree(stbuf->extension);
20762e39417SDominique Martinet 	stbuf->extension = NULL;
208ace51c4dSEric Van Hensbergen }
209ace51c4dSEric Van Hensbergen EXPORT_SYMBOL(p9stat_free);
210ace51c4dSEric Van Hensbergen 
pdu_read(struct p9_fcall * pdu,void * data,size_t size)211abfa034eSAneesh Kumar K.V size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
212ace51c4dSEric Van Hensbergen {
21301b0c5cfSThiago Farina 	size_t len = min(pdu->size - pdu->offset, size);
2146e195b0fSDominique Martinet 
215ace51c4dSEric Van Hensbergen 	memcpy(data, &pdu->sdata[pdu->offset], len);
216ace51c4dSEric Van Hensbergen 	pdu->offset += len;
217ace51c4dSEric Van Hensbergen 	return size - len;
218ace51c4dSEric Van Hensbergen }
219ace51c4dSEric Van Hensbergen 
pdu_write(struct p9_fcall * pdu,const void * data,size_t size)220ace51c4dSEric Van Hensbergen static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
221ace51c4dSEric Van Hensbergen {
22201b0c5cfSThiago Farina 	size_t len = min(pdu->capacity - pdu->size, size);
2236e195b0fSDominique Martinet 
224ace51c4dSEric Van Hensbergen 	memcpy(&pdu->sdata[pdu->size], data, len);
225ace51c4dSEric Van Hensbergen 	pdu->size += len;
226ace51c4dSEric Van Hensbergen 	return size - len;
227ace51c4dSEric Van Hensbergen }
228ace51c4dSEric Van Hensbergen 
22951a87c55SEric Van Hensbergen static size_t
pdu_write_u(struct p9_fcall * pdu,struct iov_iter * from,size_t size)2304f3b35c1SAl Viro pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size)
23151a87c55SEric Van Hensbergen {
23201b0c5cfSThiago Farina 	size_t len = min(pdu->capacity - pdu->size, size);
2336e195b0fSDominique Martinet 
2347f024647SAl Viro 	if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, from))
2357b3bb3feSAneesh Kumar K.V 		len = 0;
23651a87c55SEric Van Hensbergen 
23751a87c55SEric Van Hensbergen 	pdu->size += len;
23851a87c55SEric Van Hensbergen 	return size - len;
23951a87c55SEric Van Hensbergen }
24051a87c55SEric Van Hensbergen 
2416e195b0fSDominique Martinet /*	b - int8_t
2426e195b0fSDominique Martinet  *	w - int16_t
2436e195b0fSDominique Martinet  *	d - int32_t
2446e195b0fSDominique Martinet  *	q - int64_t
2456e195b0fSDominique Martinet  *	s - string
2466e195b0fSDominique Martinet  *	u - numeric uid
2476e195b0fSDominique Martinet  *	g - numeric gid
2486e195b0fSDominique Martinet  *	S - stat
2496e195b0fSDominique Martinet  *	Q - qid
2506e195b0fSDominique Martinet  *	D - data blob (int32_t size followed by void *, results are not freed)
2516e195b0fSDominique Martinet  *	T - array of strings (int16_t count, followed by strings)
2526e195b0fSDominique Martinet  *	R - array of qids (int16_t count, followed by qids)
2536e195b0fSDominique Martinet  *	A - stat for 9p2000.L (p9_stat_dotl)
2546e195b0fSDominique Martinet  *	? - if optional = 1, continue parsing
255ace51c4dSEric Van Hensbergen  */
256ace51c4dSEric Van Hensbergen 
257ace51c4dSEric Van Hensbergen static int
p9pdu_vreadf(struct p9_fcall * pdu,int proto_version,const char * fmt,va_list ap)258342fee1dSSripathi Kodi p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
259342fee1dSSripathi Kodi 	     va_list ap)
260ace51c4dSEric Van Hensbergen {
261ace51c4dSEric Van Hensbergen 	const char *ptr;
262ace51c4dSEric Van Hensbergen 	int errcode = 0;
263ace51c4dSEric Van Hensbergen 
264ace51c4dSEric Van Hensbergen 	for (ptr = fmt; *ptr; ptr++) {
265ace51c4dSEric Van Hensbergen 		switch (*ptr) {
266ace51c4dSEric Van Hensbergen 		case 'b':{
267ace51c4dSEric Van Hensbergen 				int8_t *val = va_arg(ap, int8_t *);
268ace51c4dSEric Van Hensbergen 				if (pdu_read(pdu, val, sizeof(*val))) {
269ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
270ace51c4dSEric Van Hensbergen 					break;
271ace51c4dSEric Van Hensbergen 				}
272ace51c4dSEric Van Hensbergen 			}
273ace51c4dSEric Van Hensbergen 			break;
274ace51c4dSEric Van Hensbergen 		case 'w':{
275ace51c4dSEric Van Hensbergen 				int16_t *val = va_arg(ap, int16_t *);
276beeebc92SEric Van Hensbergen 				__le16 le_val;
277beeebc92SEric Van Hensbergen 				if (pdu_read(pdu, &le_val, sizeof(le_val))) {
278ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
279ace51c4dSEric Van Hensbergen 					break;
280ace51c4dSEric Van Hensbergen 				}
281beeebc92SEric Van Hensbergen 				*val = le16_to_cpu(le_val);
282ace51c4dSEric Van Hensbergen 			}
283ace51c4dSEric Van Hensbergen 			break;
284ace51c4dSEric Van Hensbergen 		case 'd':{
285ace51c4dSEric Van Hensbergen 				int32_t *val = va_arg(ap, int32_t *);
286beeebc92SEric Van Hensbergen 				__le32 le_val;
287beeebc92SEric Van Hensbergen 				if (pdu_read(pdu, &le_val, sizeof(le_val))) {
288ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
289ace51c4dSEric Van Hensbergen 					break;
290ace51c4dSEric Van Hensbergen 				}
291beeebc92SEric Van Hensbergen 				*val = le32_to_cpu(le_val);
292ace51c4dSEric Van Hensbergen 			}
293ace51c4dSEric Van Hensbergen 			break;
294ace51c4dSEric Van Hensbergen 		case 'q':{
295ace51c4dSEric Van Hensbergen 				int64_t *val = va_arg(ap, int64_t *);
296beeebc92SEric Van Hensbergen 				__le64 le_val;
297beeebc92SEric Van Hensbergen 				if (pdu_read(pdu, &le_val, sizeof(le_val))) {
298ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
299ace51c4dSEric Van Hensbergen 					break;
300ace51c4dSEric Van Hensbergen 				}
301beeebc92SEric Van Hensbergen 				*val = le64_to_cpu(le_val);
302ace51c4dSEric Van Hensbergen 			}
303ace51c4dSEric Van Hensbergen 			break;
304ace51c4dSEric Van Hensbergen 		case 's':{
305e45c5405SEric Van Hensbergen 				char **sptr = va_arg(ap, char **);
306219fd58bSM. Mohan Kumar 				uint16_t len;
307ace51c4dSEric Van Hensbergen 
308342fee1dSSripathi Kodi 				errcode = p9pdu_readf(pdu, proto_version,
309342fee1dSSripathi Kodi 								"w", &len);
310ace51c4dSEric Van Hensbergen 				if (errcode)
311ace51c4dSEric Van Hensbergen 					break;
312ace51c4dSEric Van Hensbergen 
313eeff66efSAneesh Kumar K.V 				*sptr = kmalloc(len + 1, GFP_NOFS);
314e45c5405SEric Van Hensbergen 				if (*sptr == NULL) {
315b87d1d26Spiaojun 					errcode = -ENOMEM;
316ace51c4dSEric Van Hensbergen 					break;
317ace51c4dSEric Van Hensbergen 				}
318219fd58bSM. Mohan Kumar 				if (pdu_read(pdu, *sptr, len)) {
319ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
320e45c5405SEric Van Hensbergen 					kfree(*sptr);
321e45c5405SEric Van Hensbergen 					*sptr = NULL;
322ace51c4dSEric Van Hensbergen 				} else
323219fd58bSM. Mohan Kumar 					(*sptr)[len] = 0;
324ace51c4dSEric Van Hensbergen 			}
325ace51c4dSEric Van Hensbergen 			break;
32697fc8b1eSEric W. Biederman 		case 'u': {
32797fc8b1eSEric W. Biederman 				kuid_t *uid = va_arg(ap, kuid_t *);
32897fc8b1eSEric W. Biederman 				__le32 le_val;
32997fc8b1eSEric W. Biederman 				if (pdu_read(pdu, &le_val, sizeof(le_val))) {
33097fc8b1eSEric W. Biederman 					errcode = -EFAULT;
33197fc8b1eSEric W. Biederman 					break;
33297fc8b1eSEric W. Biederman 				}
33397fc8b1eSEric W. Biederman 				*uid = make_kuid(&init_user_ns,
33497fc8b1eSEric W. Biederman 						 le32_to_cpu(le_val));
33597fc8b1eSEric W. Biederman 			} break;
33697fc8b1eSEric W. Biederman 		case 'g': {
33797fc8b1eSEric W. Biederman 				kgid_t *gid = va_arg(ap, kgid_t *);
33897fc8b1eSEric W. Biederman 				__le32 le_val;
33997fc8b1eSEric W. Biederman 				if (pdu_read(pdu, &le_val, sizeof(le_val))) {
34097fc8b1eSEric W. Biederman 					errcode = -EFAULT;
34197fc8b1eSEric W. Biederman 					break;
34297fc8b1eSEric W. Biederman 				}
34397fc8b1eSEric W. Biederman 				*gid = make_kgid(&init_user_ns,
34497fc8b1eSEric W. Biederman 						 le32_to_cpu(le_val));
34597fc8b1eSEric W. Biederman 			} break;
346ace51c4dSEric Van Hensbergen 		case 'Q':{
347ace51c4dSEric Van Hensbergen 				struct p9_qid *qid =
348ace51c4dSEric Van Hensbergen 				    va_arg(ap, struct p9_qid *);
349ace51c4dSEric Van Hensbergen 
350342fee1dSSripathi Kodi 				errcode = p9pdu_readf(pdu, proto_version, "bdq",
351ace51c4dSEric Van Hensbergen 						      &qid->type, &qid->version,
352ace51c4dSEric Van Hensbergen 						      &qid->path);
353ace51c4dSEric Van Hensbergen 			}
354ace51c4dSEric Van Hensbergen 			break;
355ace51c4dSEric Van Hensbergen 		case 'S':{
356ace51c4dSEric Van Hensbergen 				struct p9_wstat *stbuf =
357ace51c4dSEric Van Hensbergen 				    va_arg(ap, struct p9_wstat *);
358ace51c4dSEric Van Hensbergen 
359f0a0ac2eSEric Van Hensbergen 				memset(stbuf, 0, sizeof(struct p9_wstat));
360447c5094SEric W. Biederman 				stbuf->n_uid = stbuf->n_muid = INVALID_UID;
361447c5094SEric W. Biederman 				stbuf->n_gid = INVALID_GID;
362447c5094SEric W. Biederman 
363ace51c4dSEric Van Hensbergen 				errcode =
364342fee1dSSripathi Kodi 				    p9pdu_readf(pdu, proto_version,
365447c5094SEric W. Biederman 						"wwdQdddqssss?sugu",
366ace51c4dSEric Van Hensbergen 						&stbuf->size, &stbuf->type,
367ace51c4dSEric Van Hensbergen 						&stbuf->dev, &stbuf->qid,
368ace51c4dSEric Van Hensbergen 						&stbuf->mode, &stbuf->atime,
369ace51c4dSEric Van Hensbergen 						&stbuf->mtime, &stbuf->length,
370ace51c4dSEric Van Hensbergen 						&stbuf->name, &stbuf->uid,
371ace51c4dSEric Van Hensbergen 						&stbuf->gid, &stbuf->muid,
372ace51c4dSEric Van Hensbergen 						&stbuf->extension,
373ace51c4dSEric Van Hensbergen 						&stbuf->n_uid, &stbuf->n_gid,
374ace51c4dSEric Van Hensbergen 						&stbuf->n_muid);
375ace51c4dSEric Van Hensbergen 				if (errcode)
376ace51c4dSEric Van Hensbergen 					p9stat_free(stbuf);
377ace51c4dSEric Van Hensbergen 			}
378ace51c4dSEric Van Hensbergen 			break;
379ace51c4dSEric Van Hensbergen 		case 'D':{
380219fd58bSM. Mohan Kumar 				uint32_t *count = va_arg(ap, uint32_t *);
381ace51c4dSEric Van Hensbergen 				void **data = va_arg(ap, void **);
382ace51c4dSEric Van Hensbergen 
383ace51c4dSEric Van Hensbergen 				errcode =
384342fee1dSSripathi Kodi 				    p9pdu_readf(pdu, proto_version, "d", count);
385ace51c4dSEric Van Hensbergen 				if (!errcode) {
386ace51c4dSEric Van Hensbergen 					*count =
387219fd58bSM. Mohan Kumar 					    min_t(uint32_t, *count,
388ace51c4dSEric Van Hensbergen 						  pdu->size - pdu->offset);
389ace51c4dSEric Van Hensbergen 					*data = &pdu->sdata[pdu->offset];
390ace51c4dSEric Van Hensbergen 				}
391ace51c4dSEric Van Hensbergen 			}
392ace51c4dSEric Van Hensbergen 			break;
393ace51c4dSEric Van Hensbergen 		case 'T':{
394b76225e2SHarsh Prateek Bora 				uint16_t *nwname = va_arg(ap, uint16_t *);
395ace51c4dSEric Van Hensbergen 				char ***wnames = va_arg(ap, char ***);
396ace51c4dSEric Van Hensbergen 
397*506ef81cSFedor Pchelkin 				*wnames = NULL;
398*506ef81cSFedor Pchelkin 
399342fee1dSSripathi Kodi 				errcode = p9pdu_readf(pdu, proto_version,
400342fee1dSSripathi Kodi 								"w", nwname);
401ace51c4dSEric Van Hensbergen 				if (!errcode) {
402ace51c4dSEric Van Hensbergen 					*wnames =
4036da2ec56SKees Cook 					    kmalloc_array(*nwname,
4046da2ec56SKees Cook 							  sizeof(char *),
405eeff66efSAneesh Kumar K.V 							  GFP_NOFS);
406ace51c4dSEric Van Hensbergen 					if (!*wnames)
407ace51c4dSEric Van Hensbergen 						errcode = -ENOMEM;
408*506ef81cSFedor Pchelkin 					else
409*506ef81cSFedor Pchelkin 						(*wnames)[0] = NULL;
410ace51c4dSEric Van Hensbergen 				}
411ace51c4dSEric Van Hensbergen 
412ace51c4dSEric Van Hensbergen 				if (!errcode) {
413ace51c4dSEric Van Hensbergen 					int i;
414ace51c4dSEric Van Hensbergen 
415ace51c4dSEric Van Hensbergen 					for (i = 0; i < *nwname; i++) {
416ace51c4dSEric Van Hensbergen 						errcode =
417342fee1dSSripathi Kodi 						    p9pdu_readf(pdu,
418342fee1dSSripathi Kodi 								proto_version,
419ace51c4dSEric Van Hensbergen 								"s",
420ace51c4dSEric Van Hensbergen 								&(*wnames)[i]);
421*506ef81cSFedor Pchelkin 						if (errcode) {
422*506ef81cSFedor Pchelkin 							(*wnames)[i] = NULL;
423ace51c4dSEric Van Hensbergen 							break;
424ace51c4dSEric Van Hensbergen 						}
425ace51c4dSEric Van Hensbergen 					}
426*506ef81cSFedor Pchelkin 				}
427ace51c4dSEric Van Hensbergen 
428ace51c4dSEric Van Hensbergen 				if (errcode) {
429ace51c4dSEric Van Hensbergen 					if (*wnames) {
430ace51c4dSEric Van Hensbergen 						int i;
431ace51c4dSEric Van Hensbergen 
432*506ef81cSFedor Pchelkin 						for (i = 0; i < *nwname; i++) {
433*506ef81cSFedor Pchelkin 							if (!(*wnames)[i])
434*506ef81cSFedor Pchelkin 								break;
435ace51c4dSEric Van Hensbergen 							kfree((*wnames)[i]);
436ace51c4dSEric Van Hensbergen 						}
437ace51c4dSEric Van Hensbergen 						kfree(*wnames);
438ace51c4dSEric Van Hensbergen 						*wnames = NULL;
439ace51c4dSEric Van Hensbergen 					}
440ace51c4dSEric Van Hensbergen 				}
441*506ef81cSFedor Pchelkin 			}
442ace51c4dSEric Van Hensbergen 			break;
443ace51c4dSEric Van Hensbergen 		case 'R':{
4446250a8baSKirill A. Shutemov 				uint16_t *nwqid = va_arg(ap, uint16_t *);
445ace51c4dSEric Van Hensbergen 				struct p9_qid **wqids =
446ace51c4dSEric Van Hensbergen 				    va_arg(ap, struct p9_qid **);
447ace51c4dSEric Van Hensbergen 
448ace51c4dSEric Van Hensbergen 				*wqids = NULL;
449ace51c4dSEric Van Hensbergen 
450ace51c4dSEric Van Hensbergen 				errcode =
451342fee1dSSripathi Kodi 				    p9pdu_readf(pdu, proto_version, "w", nwqid);
452ace51c4dSEric Van Hensbergen 				if (!errcode) {
453ace51c4dSEric Van Hensbergen 					*wqids =
4546da2ec56SKees Cook 					    kmalloc_array(*nwqid,
455ace51c4dSEric Van Hensbergen 							  sizeof(struct p9_qid),
456eeff66efSAneesh Kumar K.V 							  GFP_NOFS);
457ace51c4dSEric Van Hensbergen 					if (*wqids == NULL)
458ace51c4dSEric Van Hensbergen 						errcode = -ENOMEM;
459ace51c4dSEric Van Hensbergen 				}
460ace51c4dSEric Van Hensbergen 
461ace51c4dSEric Van Hensbergen 				if (!errcode) {
462ace51c4dSEric Van Hensbergen 					int i;
463ace51c4dSEric Van Hensbergen 
464ace51c4dSEric Van Hensbergen 					for (i = 0; i < *nwqid; i++) {
465ace51c4dSEric Van Hensbergen 						errcode =
466342fee1dSSripathi Kodi 						    p9pdu_readf(pdu,
467342fee1dSSripathi Kodi 								proto_version,
468ace51c4dSEric Van Hensbergen 								"Q",
469ace51c4dSEric Van Hensbergen 								&(*wqids)[i]);
470ace51c4dSEric Van Hensbergen 						if (errcode)
471ace51c4dSEric Van Hensbergen 							break;
472ace51c4dSEric Van Hensbergen 					}
473ace51c4dSEric Van Hensbergen 				}
474ace51c4dSEric Van Hensbergen 
475ace51c4dSEric Van Hensbergen 				if (errcode) {
476ace51c4dSEric Van Hensbergen 					kfree(*wqids);
477ace51c4dSEric Van Hensbergen 					*wqids = NULL;
478ace51c4dSEric Van Hensbergen 				}
479ace51c4dSEric Van Hensbergen 			}
480ace51c4dSEric Van Hensbergen 			break;
481f0853122SSripathi Kodi 		case 'A': {
482f0853122SSripathi Kodi 				struct p9_stat_dotl *stbuf =
483f0853122SSripathi Kodi 				    va_arg(ap, struct p9_stat_dotl *);
484f0853122SSripathi Kodi 
485f0853122SSripathi Kodi 				memset(stbuf, 0, sizeof(struct p9_stat_dotl));
486f0853122SSripathi Kodi 				errcode =
487f0853122SSripathi Kodi 				    p9pdu_readf(pdu, proto_version,
488447c5094SEric W. Biederman 					"qQdugqqqqqqqqqqqqqqq",
489f0853122SSripathi Kodi 					&stbuf->st_result_mask,
490f0853122SSripathi Kodi 					&stbuf->qid,
491f0853122SSripathi Kodi 					&stbuf->st_mode,
492f0853122SSripathi Kodi 					&stbuf->st_uid, &stbuf->st_gid,
493f0853122SSripathi Kodi 					&stbuf->st_nlink,
494f0853122SSripathi Kodi 					&stbuf->st_rdev, &stbuf->st_size,
495f0853122SSripathi Kodi 					&stbuf->st_blksize, &stbuf->st_blocks,
496f0853122SSripathi Kodi 					&stbuf->st_atime_sec,
497f0853122SSripathi Kodi 					&stbuf->st_atime_nsec,
498f0853122SSripathi Kodi 					&stbuf->st_mtime_sec,
499f0853122SSripathi Kodi 					&stbuf->st_mtime_nsec,
500f0853122SSripathi Kodi 					&stbuf->st_ctime_sec,
501f0853122SSripathi Kodi 					&stbuf->st_ctime_nsec,
502f0853122SSripathi Kodi 					&stbuf->st_btime_sec,
503f0853122SSripathi Kodi 					&stbuf->st_btime_nsec,
504f0853122SSripathi Kodi 					&stbuf->st_gen,
505f0853122SSripathi Kodi 					&stbuf->st_data_version);
506f0853122SSripathi Kodi 			}
507f0853122SSripathi Kodi 			break;
508ace51c4dSEric Van Hensbergen 		case '?':
509c56e4acfSSripathi Kodi 			if ((proto_version != p9_proto_2000u) &&
510c56e4acfSSripathi Kodi 				(proto_version != p9_proto_2000L))
511ace51c4dSEric Van Hensbergen 				return 0;
512ace51c4dSEric Van Hensbergen 			break;
513ace51c4dSEric Van Hensbergen 		default:
514ace51c4dSEric Van Hensbergen 			BUG();
515ace51c4dSEric Van Hensbergen 			break;
516ace51c4dSEric Van Hensbergen 		}
517ace51c4dSEric Van Hensbergen 
518ace51c4dSEric Van Hensbergen 		if (errcode)
519ace51c4dSEric Van Hensbergen 			break;
520ace51c4dSEric Van Hensbergen 	}
521ace51c4dSEric Van Hensbergen 
522ace51c4dSEric Van Hensbergen 	return errcode;
523ace51c4dSEric Van Hensbergen }
524ace51c4dSEric Van Hensbergen 
525ace51c4dSEric Van Hensbergen int
p9pdu_vwritef(struct p9_fcall * pdu,int proto_version,const char * fmt,va_list ap)526342fee1dSSripathi Kodi p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
527342fee1dSSripathi Kodi 	va_list ap)
528ace51c4dSEric Van Hensbergen {
529ace51c4dSEric Van Hensbergen 	const char *ptr;
530ace51c4dSEric Van Hensbergen 	int errcode = 0;
531ace51c4dSEric Van Hensbergen 
532ace51c4dSEric Van Hensbergen 	for (ptr = fmt; *ptr; ptr++) {
533ace51c4dSEric Van Hensbergen 		switch (*ptr) {
534ace51c4dSEric Van Hensbergen 		case 'b':{
535ace51c4dSEric Van Hensbergen 				int8_t val = va_arg(ap, int);
536ace51c4dSEric Van Hensbergen 				if (pdu_write(pdu, &val, sizeof(val)))
537ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
538ace51c4dSEric Van Hensbergen 			}
539ace51c4dSEric Van Hensbergen 			break;
540ace51c4dSEric Van Hensbergen 		case 'w':{
541beeebc92SEric Van Hensbergen 				__le16 val = cpu_to_le16(va_arg(ap, int));
542ace51c4dSEric Van Hensbergen 				if (pdu_write(pdu, &val, sizeof(val)))
543ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
544ace51c4dSEric Van Hensbergen 			}
545ace51c4dSEric Van Hensbergen 			break;
546ace51c4dSEric Van Hensbergen 		case 'd':{
547beeebc92SEric Van Hensbergen 				__le32 val = cpu_to_le32(va_arg(ap, int32_t));
548ace51c4dSEric Van Hensbergen 				if (pdu_write(pdu, &val, sizeof(val)))
549ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
550ace51c4dSEric Van Hensbergen 			}
551ace51c4dSEric Van Hensbergen 			break;
552ace51c4dSEric Van Hensbergen 		case 'q':{
553beeebc92SEric Van Hensbergen 				__le64 val = cpu_to_le64(va_arg(ap, int64_t));
554ace51c4dSEric Van Hensbergen 				if (pdu_write(pdu, &val, sizeof(val)))
555ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
556ace51c4dSEric Van Hensbergen 			}
557ace51c4dSEric Van Hensbergen 			break;
558ace51c4dSEric Van Hensbergen 		case 's':{
559e45c5405SEric Van Hensbergen 				const char *sptr = va_arg(ap, const char *);
560219fd58bSM. Mohan Kumar 				uint16_t len = 0;
561e45c5405SEric Van Hensbergen 				if (sptr)
562d31bb4f0SDan Carpenter 					len = min_t(size_t, strlen(sptr),
563219fd58bSM. Mohan Kumar 								USHRT_MAX);
564ace51c4dSEric Van Hensbergen 
565342fee1dSSripathi Kodi 				errcode = p9pdu_writef(pdu, proto_version,
566342fee1dSSripathi Kodi 								"w", len);
567e45c5405SEric Van Hensbergen 				if (!errcode && pdu_write(pdu, sptr, len))
568ace51c4dSEric Van Hensbergen 					errcode = -EFAULT;
569ace51c4dSEric Van Hensbergen 			}
570ace51c4dSEric Van Hensbergen 			break;
57197fc8b1eSEric W. Biederman 		case 'u': {
57297fc8b1eSEric W. Biederman 				kuid_t uid = va_arg(ap, kuid_t);
57397fc8b1eSEric W. Biederman 				__le32 val = cpu_to_le32(
57497fc8b1eSEric W. Biederman 						from_kuid(&init_user_ns, uid));
57597fc8b1eSEric W. Biederman 				if (pdu_write(pdu, &val, sizeof(val)))
57697fc8b1eSEric W. Biederman 					errcode = -EFAULT;
57797fc8b1eSEric W. Biederman 			} break;
57897fc8b1eSEric W. Biederman 		case 'g': {
57997fc8b1eSEric W. Biederman 				kgid_t gid = va_arg(ap, kgid_t);
58097fc8b1eSEric W. Biederman 				__le32 val = cpu_to_le32(
58197fc8b1eSEric W. Biederman 						from_kgid(&init_user_ns, gid));
58297fc8b1eSEric W. Biederman 				if (pdu_write(pdu, &val, sizeof(val)))
58397fc8b1eSEric W. Biederman 					errcode = -EFAULT;
58497fc8b1eSEric W. Biederman 			} break;
585ace51c4dSEric Van Hensbergen 		case 'Q':{
586ace51c4dSEric Van Hensbergen 				const struct p9_qid *qid =
587ace51c4dSEric Van Hensbergen 				    va_arg(ap, const struct p9_qid *);
588ace51c4dSEric Van Hensbergen 				errcode =
589342fee1dSSripathi Kodi 				    p9pdu_writef(pdu, proto_version, "bdq",
590ace51c4dSEric Van Hensbergen 						 qid->type, qid->version,
591ace51c4dSEric Van Hensbergen 						 qid->path);
592ace51c4dSEric Van Hensbergen 			} break;
593ace51c4dSEric Van Hensbergen 		case 'S':{
594ace51c4dSEric Van Hensbergen 				const struct p9_wstat *stbuf =
595ace51c4dSEric Van Hensbergen 				    va_arg(ap, const struct p9_wstat *);
596ace51c4dSEric Van Hensbergen 				errcode =
597342fee1dSSripathi Kodi 				    p9pdu_writef(pdu, proto_version,
598447c5094SEric W. Biederman 						 "wwdQdddqssss?sugu",
599ace51c4dSEric Van Hensbergen 						 stbuf->size, stbuf->type,
60051a87c55SEric Van Hensbergen 						 stbuf->dev, &stbuf->qid,
601ace51c4dSEric Van Hensbergen 						 stbuf->mode, stbuf->atime,
602ace51c4dSEric Van Hensbergen 						 stbuf->mtime, stbuf->length,
603ace51c4dSEric Van Hensbergen 						 stbuf->name, stbuf->uid,
604ace51c4dSEric Van Hensbergen 						 stbuf->gid, stbuf->muid,
605ace51c4dSEric Van Hensbergen 						 stbuf->extension, stbuf->n_uid,
606ace51c4dSEric Van Hensbergen 						 stbuf->n_gid, stbuf->n_muid);
607ace51c4dSEric Van Hensbergen 			} break;
6084f3b35c1SAl Viro 		case 'V':{
609219fd58bSM. Mohan Kumar 				uint32_t count = va_arg(ap, uint32_t);
6104f3b35c1SAl Viro 				struct iov_iter *from =
6114f3b35c1SAl Viro 						va_arg(ap, struct iov_iter *);
612342fee1dSSripathi Kodi 				errcode = p9pdu_writef(pdu, proto_version, "d",
613342fee1dSSripathi Kodi 									count);
6144f3b35c1SAl Viro 				if (!errcode && pdu_write_u(pdu, from, count))
61551a87c55SEric Van Hensbergen 					errcode = -EFAULT;
61651a87c55SEric Van Hensbergen 			}
61751a87c55SEric Van Hensbergen 			break;
618ace51c4dSEric Van Hensbergen 		case 'T':{
619b76225e2SHarsh Prateek Bora 				uint16_t nwname = va_arg(ap, int);
620ace51c4dSEric Van Hensbergen 				const char **wnames = va_arg(ap, const char **);
621ace51c4dSEric Van Hensbergen 
622342fee1dSSripathi Kodi 				errcode = p9pdu_writef(pdu, proto_version, "w",
623342fee1dSSripathi Kodi 									nwname);
624ace51c4dSEric Van Hensbergen 				if (!errcode) {
625ace51c4dSEric Van Hensbergen 					int i;
626ace51c4dSEric Van Hensbergen 
627ace51c4dSEric Van Hensbergen 					for (i = 0; i < nwname; i++) {
628ace51c4dSEric Van Hensbergen 						errcode =
629342fee1dSSripathi Kodi 						    p9pdu_writef(pdu,
630342fee1dSSripathi Kodi 								proto_version,
631ace51c4dSEric Van Hensbergen 								 "s",
632ace51c4dSEric Van Hensbergen 								 wnames[i]);
633ace51c4dSEric Van Hensbergen 						if (errcode)
634ace51c4dSEric Van Hensbergen 							break;
635ace51c4dSEric Van Hensbergen 					}
636ace51c4dSEric Van Hensbergen 				}
637ace51c4dSEric Van Hensbergen 			}
638ace51c4dSEric Van Hensbergen 			break;
639ace51c4dSEric Van Hensbergen 		case 'R':{
6406250a8baSKirill A. Shutemov 				uint16_t nwqid = va_arg(ap, int);
641ace51c4dSEric Van Hensbergen 				struct p9_qid *wqids =
642ace51c4dSEric Van Hensbergen 				    va_arg(ap, struct p9_qid *);
643ace51c4dSEric Van Hensbergen 
644342fee1dSSripathi Kodi 				errcode = p9pdu_writef(pdu, proto_version, "w",
645342fee1dSSripathi Kodi 									nwqid);
646ace51c4dSEric Van Hensbergen 				if (!errcode) {
647ace51c4dSEric Van Hensbergen 					int i;
648ace51c4dSEric Van Hensbergen 
649ace51c4dSEric Van Hensbergen 					for (i = 0; i < nwqid; i++) {
650ace51c4dSEric Van Hensbergen 						errcode =
651342fee1dSSripathi Kodi 						    p9pdu_writef(pdu,
652342fee1dSSripathi Kodi 								proto_version,
653ace51c4dSEric Van Hensbergen 								 "Q",
654ace51c4dSEric Van Hensbergen 								 &wqids[i]);
655ace51c4dSEric Van Hensbergen 						if (errcode)
656ace51c4dSEric Van Hensbergen 							break;
657ace51c4dSEric Van Hensbergen 					}
658ace51c4dSEric Van Hensbergen 				}
659ace51c4dSEric Van Hensbergen 			}
660ace51c4dSEric Van Hensbergen 			break;
66187d7845aSSripathi Kodi 		case 'I':{
66287d7845aSSripathi Kodi 				struct p9_iattr_dotl *p9attr = va_arg(ap,
66387d7845aSSripathi Kodi 							struct p9_iattr_dotl *);
66487d7845aSSripathi Kodi 
66587d7845aSSripathi Kodi 				errcode = p9pdu_writef(pdu, proto_version,
666447c5094SEric W. Biederman 							"ddugqqqqq",
66787d7845aSSripathi Kodi 							p9attr->valid,
66887d7845aSSripathi Kodi 							p9attr->mode,
66987d7845aSSripathi Kodi 							p9attr->uid,
67087d7845aSSripathi Kodi 							p9attr->gid,
67187d7845aSSripathi Kodi 							p9attr->size,
67287d7845aSSripathi Kodi 							p9attr->atime_sec,
67387d7845aSSripathi Kodi 							p9attr->atime_nsec,
67487d7845aSSripathi Kodi 							p9attr->mtime_sec,
67587d7845aSSripathi Kodi 							p9attr->mtime_nsec);
67687d7845aSSripathi Kodi 			}
67787d7845aSSripathi Kodi 			break;
678ace51c4dSEric Van Hensbergen 		case '?':
679c56e4acfSSripathi Kodi 			if ((proto_version != p9_proto_2000u) &&
680c56e4acfSSripathi Kodi 				(proto_version != p9_proto_2000L))
681ace51c4dSEric Van Hensbergen 				return 0;
682ace51c4dSEric Van Hensbergen 			break;
683ace51c4dSEric Van Hensbergen 		default:
684ace51c4dSEric Van Hensbergen 			BUG();
685ace51c4dSEric Van Hensbergen 			break;
686ace51c4dSEric Van Hensbergen 		}
687ace51c4dSEric Van Hensbergen 
688ace51c4dSEric Van Hensbergen 		if (errcode)
689ace51c4dSEric Van Hensbergen 			break;
690ace51c4dSEric Van Hensbergen 	}
691ace51c4dSEric Van Hensbergen 
692ace51c4dSEric Van Hensbergen 	return errcode;
693ace51c4dSEric Van Hensbergen }
694ace51c4dSEric Van Hensbergen 
p9pdu_readf(struct p9_fcall * pdu,int proto_version,const char * fmt,...)695342fee1dSSripathi Kodi int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
696ace51c4dSEric Van Hensbergen {
697ace51c4dSEric Van Hensbergen 	va_list ap;
698ace51c4dSEric Van Hensbergen 	int ret;
699ace51c4dSEric Van Hensbergen 
700ace51c4dSEric Van Hensbergen 	va_start(ap, fmt);
701342fee1dSSripathi Kodi 	ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
702ace51c4dSEric Van Hensbergen 	va_end(ap);
703ace51c4dSEric Van Hensbergen 
704ace51c4dSEric Van Hensbergen 	return ret;
705ace51c4dSEric Van Hensbergen }
706ace51c4dSEric Van Hensbergen 
707ace51c4dSEric Van Hensbergen static int
p9pdu_writef(struct p9_fcall * pdu,int proto_version,const char * fmt,...)708342fee1dSSripathi Kodi p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
709ace51c4dSEric Van Hensbergen {
710ace51c4dSEric Van Hensbergen 	va_list ap;
711ace51c4dSEric Van Hensbergen 	int ret;
712ace51c4dSEric Van Hensbergen 
713ace51c4dSEric Van Hensbergen 	va_start(ap, fmt);
714342fee1dSSripathi Kodi 	ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
715ace51c4dSEric Van Hensbergen 	va_end(ap);
716ace51c4dSEric Van Hensbergen 
717ace51c4dSEric Van Hensbergen 	return ret;
718ace51c4dSEric Van Hensbergen }
71951a87c55SEric Van Hensbergen 
p9stat_read(struct p9_client * clnt,char * buf,int len,struct p9_wstat * st)720348b5901SAneesh Kumar K.V int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
72102da398bSEric Van Hensbergen {
72202da398bSEric Van Hensbergen 	struct p9_fcall fake_pdu;
723e7f4b8f1SEric Van Hensbergen 	int ret;
72402da398bSEric Van Hensbergen 
72502da398bSEric Van Hensbergen 	fake_pdu.size = len;
72602da398bSEric Van Hensbergen 	fake_pdu.capacity = len;
72702da398bSEric Van Hensbergen 	fake_pdu.sdata = buf;
72802da398bSEric Van Hensbergen 	fake_pdu.offset = 0;
72902da398bSEric Van Hensbergen 
730348b5901SAneesh Kumar K.V 	ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);
731e7f4b8f1SEric Van Hensbergen 	if (ret) {
7325d385153SJoe Perches 		p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
733348b5901SAneesh Kumar K.V 		trace_9p_protocol_dump(clnt, &fake_pdu);
7342803cf43SGertjan Halkes 		return ret;
735e7f4b8f1SEric Van Hensbergen 	}
736e7f4b8f1SEric Van Hensbergen 
7372803cf43SGertjan Halkes 	return fake_pdu.offset;
73802da398bSEric Van Hensbergen }
73902da398bSEric Van Hensbergen EXPORT_SYMBOL(p9stat_read);
74002da398bSEric Van Hensbergen 
p9pdu_prepare(struct p9_fcall * pdu,int16_t tag,int8_t type)74151a87c55SEric Van Hensbergen int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
74251a87c55SEric Van Hensbergen {
7439bb6c10aSVenkateswararao Jujjuri (JV) 	pdu->id = type;
74451a87c55SEric Van Hensbergen 	return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
74551a87c55SEric Van Hensbergen }
74651a87c55SEric Van Hensbergen 
p9pdu_finalize(struct p9_client * clnt,struct p9_fcall * pdu)747348b5901SAneesh Kumar K.V int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)
74851a87c55SEric Van Hensbergen {
74951a87c55SEric Van Hensbergen 	int size = pdu->size;
75051a87c55SEric Van Hensbergen 	int err;
75151a87c55SEric Van Hensbergen 
75251a87c55SEric Van Hensbergen 	pdu->size = 0;
75351a87c55SEric Van Hensbergen 	err = p9pdu_writef(pdu, 0, "d", size);
75451a87c55SEric Van Hensbergen 	pdu->size = size;
75551a87c55SEric Van Hensbergen 
756348b5901SAneesh Kumar K.V 	trace_9p_protocol_dump(clnt, pdu);
7575d385153SJoe Perches 	p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n",
7585d385153SJoe Perches 		 pdu->size, pdu->id, pdu->tag);
759e7f4b8f1SEric Van Hensbergen 
76051a87c55SEric Van Hensbergen 	return err;
76151a87c55SEric Van Hensbergen }
76251a87c55SEric Van Hensbergen 
p9pdu_reset(struct p9_fcall * pdu)76351a87c55SEric Van Hensbergen void p9pdu_reset(struct p9_fcall *pdu)
76451a87c55SEric Van Hensbergen {
76551a87c55SEric Van Hensbergen 	pdu->offset = 0;
76651a87c55SEric Van Hensbergen 	pdu->size = 0;
76751a87c55SEric Van Hensbergen }
7687751bdb3SSripathi Kodi 
p9dirent_read(struct p9_client * clnt,char * buf,int len,struct p9_dirent * dirent)769348b5901SAneesh Kumar K.V int p9dirent_read(struct p9_client *clnt, char *buf, int len,
770348b5901SAneesh Kumar K.V 		  struct p9_dirent *dirent)
7717751bdb3SSripathi Kodi {
7727751bdb3SSripathi Kodi 	struct p9_fcall fake_pdu;
7737751bdb3SSripathi Kodi 	int ret;
7747751bdb3SSripathi Kodi 	char *nameptr;
7757751bdb3SSripathi Kodi 
7767751bdb3SSripathi Kodi 	fake_pdu.size = len;
7777751bdb3SSripathi Kodi 	fake_pdu.capacity = len;
7787751bdb3SSripathi Kodi 	fake_pdu.sdata = buf;
7797751bdb3SSripathi Kodi 	fake_pdu.offset = 0;
7807751bdb3SSripathi Kodi 
781348b5901SAneesh Kumar K.V 	ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid,
7827751bdb3SSripathi Kodi 			  &dirent->d_off, &dirent->d_type, &nameptr);
7837751bdb3SSripathi Kodi 	if (ret) {
7845d385153SJoe Perches 		p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
785348b5901SAneesh Kumar K.V 		trace_9p_protocol_dump(clnt, &fake_pdu);
786ef5305f1SDominique Martinet 		return ret;
7877751bdb3SSripathi Kodi 	}
7887751bdb3SSripathi Kodi 
789ef5305f1SDominique Martinet 	ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
790ef5305f1SDominique Martinet 	if (ret < 0) {
791ef5305f1SDominique Martinet 		p9_debug(P9_DEBUG_ERROR,
792ef5305f1SDominique Martinet 			 "On the wire dirent name too long: %s\n",
793ef5305f1SDominique Martinet 			 nameptr);
794ef5305f1SDominique Martinet 		kfree(nameptr);
795ef5305f1SDominique Martinet 		return ret;
796ef5305f1SDominique Martinet 	}
7971b0bcbcfSPedro Scarapicchia Junior 	kfree(nameptr);
7987751bdb3SSripathi Kodi 
7997751bdb3SSripathi Kodi 	return fake_pdu.offset;
8007751bdb3SSripathi Kodi }
8017751bdb3SSripathi Kodi EXPORT_SYMBOL(p9dirent_read);
802