Merge tag 'drm-misc-next-2024-02-08' into msm-next
[sfrench/cifs-2.6.git] / net / 9p / protocol.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * 9P Protocol Support Code
4  *
5  *  Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
6  *
7  *  Base on code from Anthony Liguori <aliguori@us.ibm.com>
8  *  Copyright (C) 2008 by IBM, Corp.
9  */
10
11 #include <linux/module.h>
12 #include <linux/errno.h>
13 #include <linux/kernel.h>
14 #include <linux/uaccess.h>
15 #include <linux/slab.h>
16 #include <linux/sched.h>
17 #include <linux/stddef.h>
18 #include <linux/types.h>
19 #include <linux/uio.h>
20 #include <net/9p/9p.h>
21 #include <net/9p/client.h>
22 #include "protocol.h"
23
24 #include <trace/events/9p.h>
25
26 /* len[2] text[len] */
27 #define P9_STRLEN(s) \
28         (2 + min_t(size_t, s ? strlen(s) : 0, USHRT_MAX))
29
30 /**
31  * p9_msg_buf_size - Returns a buffer size sufficiently large to hold the
32  * intended 9p message.
33  * @c: client
34  * @type: message type
35  * @fmt: format template for assembling request message
36  * (see p9pdu_vwritef)
37  * @ap: variable arguments to be fed to passed format template
38  * (see p9pdu_vwritef)
39  *
40  * Note: Even for response types (P9_R*) the format template and variable
41  * arguments must always be for the originating request type (P9_T*).
42  */
43 size_t p9_msg_buf_size(struct p9_client *c, enum p9_msg_t type,
44                         const char *fmt, va_list ap)
45 {
46         /* size[4] type[1] tag[2] */
47         const int hdr = 4 + 1 + 2;
48         /* ename[s] errno[4] */
49         const int rerror_size = hdr + P9_ERRMAX + 4;
50         /* ecode[4] */
51         const int rlerror_size = hdr + 4;
52         const int err_size =
53                 c->proto_version == p9_proto_2000L ? rlerror_size : rerror_size;
54
55         static_assert(NAME_MAX <= 4*1024, "p9_msg_buf_size() currently assumes "
56                                   "a max. allowed directory entry name length of 4k");
57
58         switch (type) {
59
60         /* message types not used at all */
61         case P9_TERROR:
62         case P9_TLERROR:
63         case P9_TAUTH:
64         case P9_RAUTH:
65                 BUG();
66
67         /* variable length & potentially large message types */
68         case P9_TATTACH:
69                 BUG_ON(strcmp("ddss?u", fmt));
70                 va_arg(ap, int32_t);
71                 va_arg(ap, int32_t);
72                 {
73                         const char *uname = va_arg(ap, const char *);
74                         const char *aname = va_arg(ap, const char *);
75                         /* fid[4] afid[4] uname[s] aname[s] n_uname[4] */
76                         return hdr + 4 + 4 + P9_STRLEN(uname) + P9_STRLEN(aname) + 4;
77                 }
78         case P9_TWALK:
79                 BUG_ON(strcmp("ddT", fmt));
80                 va_arg(ap, int32_t);
81                 va_arg(ap, int32_t);
82                 {
83                         uint i, nwname = va_arg(ap, int);
84                         size_t wname_all;
85                         const char **wnames = va_arg(ap, const char **);
86                         for (i = 0, wname_all = 0; i < nwname; ++i) {
87                                 wname_all += P9_STRLEN(wnames[i]);
88                         }
89                         /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
90                         return hdr + 4 + 4 + 2 + wname_all;
91                 }
92         case P9_RWALK:
93                 BUG_ON(strcmp("ddT", fmt));
94                 va_arg(ap, int32_t);
95                 va_arg(ap, int32_t);
96                 {
97                         uint nwname = va_arg(ap, int);
98                         /* nwqid[2] nwqid*(wqid[13]) */
99                         return max_t(size_t, hdr + 2 + nwname * 13, err_size);
100                 }
101         case P9_TCREATE:
102                 BUG_ON(strcmp("dsdb?s", fmt));
103                 va_arg(ap, int32_t);
104                 {
105                         const char *name = va_arg(ap, const char *);
106                         if (c->proto_version == p9_proto_legacy) {
107                                 /* fid[4] name[s] perm[4] mode[1] */
108                                 return hdr + 4 + P9_STRLEN(name) + 4 + 1;
109                         } else {
110                                 va_arg(ap, int32_t);
111                                 va_arg(ap, int);
112                                 {
113                                         const char *ext = va_arg(ap, const char *);
114                                         /* fid[4] name[s] perm[4] mode[1] extension[s] */
115                                         return hdr + 4 + P9_STRLEN(name) + 4 + 1 + P9_STRLEN(ext);
116                                 }
117                         }
118                 }
119         case P9_TLCREATE:
120                 BUG_ON(strcmp("dsddg", fmt));
121                 va_arg(ap, int32_t);
122                 {
123                         const char *name = va_arg(ap, const char *);
124                         /* fid[4] name[s] flags[4] mode[4] gid[4] */
125                         return hdr + 4 + P9_STRLEN(name) + 4 + 4 + 4;
126                 }
127         case P9_RREAD:
128         case P9_RREADDIR:
129                 BUG_ON(strcmp("dqd", fmt));
130                 va_arg(ap, int32_t);
131                 va_arg(ap, int64_t);
132                 {
133                         const int32_t count = va_arg(ap, int32_t);
134                         /* count[4] data[count] */
135                         return max_t(size_t, hdr + 4 + count, err_size);
136                 }
137         case P9_TWRITE:
138                 BUG_ON(strcmp("dqV", fmt));
139                 va_arg(ap, int32_t);
140                 va_arg(ap, int64_t);
141                 {
142                         const int32_t count = va_arg(ap, int32_t);
143                         /* fid[4] offset[8] count[4] data[count] */
144                         return hdr + 4 + 8 + 4 + count;
145                 }
146         case P9_TRENAMEAT:
147                 BUG_ON(strcmp("dsds", fmt));
148                 va_arg(ap, int32_t);
149                 {
150                         const char *oldname, *newname;
151                         oldname = va_arg(ap, const char *);
152                         va_arg(ap, int32_t);
153                         newname = va_arg(ap, const char *);
154                         /* olddirfid[4] oldname[s] newdirfid[4] newname[s] */
155                         return hdr + 4 + P9_STRLEN(oldname) + 4 + P9_STRLEN(newname);
156                 }
157         case P9_TSYMLINK:
158                 BUG_ON(strcmp("dssg", fmt));
159                 va_arg(ap, int32_t);
160                 {
161                         const char *name = va_arg(ap, const char *);
162                         const char *symtgt = va_arg(ap, const char *);
163                         /* fid[4] name[s] symtgt[s] gid[4] */
164                         return hdr + 4 + P9_STRLEN(name) + P9_STRLEN(symtgt) + 4;
165                 }
166
167         case P9_RERROR:
168                 return rerror_size;
169         case P9_RLERROR:
170                 return rlerror_size;
171
172         /* small message types */
173         case P9_TWSTAT:
174         case P9_RSTAT:
175         case P9_RREADLINK:
176         case P9_TXATTRWALK:
177         case P9_TXATTRCREATE:
178         case P9_TLINK:
179         case P9_TMKDIR:
180         case P9_TMKNOD:
181         case P9_TRENAME:
182         case P9_TUNLINKAT:
183         case P9_TLOCK:
184                 return 8 * 1024;
185
186         /* tiny message types */
187         default:
188                 return 4 * 1024;
189
190         }
191 }
192
193 static int
194 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
195
196 void p9stat_free(struct p9_wstat *stbuf)
197 {
198         kfree(stbuf->name);
199         stbuf->name = NULL;
200         kfree(stbuf->uid);
201         stbuf->uid = NULL;
202         kfree(stbuf->gid);
203         stbuf->gid = NULL;
204         kfree(stbuf->muid);
205         stbuf->muid = NULL;
206         kfree(stbuf->extension);
207         stbuf->extension = NULL;
208 }
209 EXPORT_SYMBOL(p9stat_free);
210
211 size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
212 {
213         size_t len = min(pdu->size - pdu->offset, size);
214
215         memcpy(data, &pdu->sdata[pdu->offset], len);
216         pdu->offset += len;
217         return size - len;
218 }
219
220 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
221 {
222         size_t len = min(pdu->capacity - pdu->size, size);
223
224         memcpy(&pdu->sdata[pdu->size], data, len);
225         pdu->size += len;
226         return size - len;
227 }
228
229 static size_t
230 pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size)
231 {
232         size_t len = min(pdu->capacity - pdu->size, size);
233
234         if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, from))
235                 len = 0;
236
237         pdu->size += len;
238         return size - len;
239 }
240
241 /*      b - int8_t
242  *      w - int16_t
243  *      d - int32_t
244  *      q - int64_t
245  *      s - string
246  *      u - numeric uid
247  *      g - numeric gid
248  *      S - stat
249  *      Q - qid
250  *      D - data blob (int32_t size followed by void *, results are not freed)
251  *      T - array of strings (int16_t count, followed by strings)
252  *      R - array of qids (int16_t count, followed by qids)
253  *      A - stat for 9p2000.L (p9_stat_dotl)
254  *      ? - if optional = 1, continue parsing
255  */
256
257 static int
258 p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
259              va_list ap)
260 {
261         const char *ptr;
262         int errcode = 0;
263
264         for (ptr = fmt; *ptr; ptr++) {
265                 switch (*ptr) {
266                 case 'b':{
267                                 int8_t *val = va_arg(ap, int8_t *);
268                                 if (pdu_read(pdu, val, sizeof(*val))) {
269                                         errcode = -EFAULT;
270                                         break;
271                                 }
272                         }
273                         break;
274                 case 'w':{
275                                 int16_t *val = va_arg(ap, int16_t *);
276                                 __le16 le_val;
277                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
278                                         errcode = -EFAULT;
279                                         break;
280                                 }
281                                 *val = le16_to_cpu(le_val);
282                         }
283                         break;
284                 case 'd':{
285                                 int32_t *val = va_arg(ap, int32_t *);
286                                 __le32 le_val;
287                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
288                                         errcode = -EFAULT;
289                                         break;
290                                 }
291                                 *val = le32_to_cpu(le_val);
292                         }
293                         break;
294                 case 'q':{
295                                 int64_t *val = va_arg(ap, int64_t *);
296                                 __le64 le_val;
297                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
298                                         errcode = -EFAULT;
299                                         break;
300                                 }
301                                 *val = le64_to_cpu(le_val);
302                         }
303                         break;
304                 case 's':{
305                                 char **sptr = va_arg(ap, char **);
306                                 uint16_t len;
307
308                                 errcode = p9pdu_readf(pdu, proto_version,
309                                                                 "w", &len);
310                                 if (errcode)
311                                         break;
312
313                                 *sptr = kmalloc(len + 1, GFP_NOFS);
314                                 if (*sptr == NULL) {
315                                         errcode = -ENOMEM;
316                                         break;
317                                 }
318                                 if (pdu_read(pdu, *sptr, len)) {
319                                         errcode = -EFAULT;
320                                         kfree(*sptr);
321                                         *sptr = NULL;
322                                 } else
323                                         (*sptr)[len] = 0;
324                         }
325                         break;
326                 case 'u': {
327                                 kuid_t *uid = va_arg(ap, kuid_t *);
328                                 __le32 le_val;
329                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
330                                         errcode = -EFAULT;
331                                         break;
332                                 }
333                                 *uid = make_kuid(&init_user_ns,
334                                                  le32_to_cpu(le_val));
335                         } break;
336                 case 'g': {
337                                 kgid_t *gid = va_arg(ap, kgid_t *);
338                                 __le32 le_val;
339                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
340                                         errcode = -EFAULT;
341                                         break;
342                                 }
343                                 *gid = make_kgid(&init_user_ns,
344                                                  le32_to_cpu(le_val));
345                         } break;
346                 case 'Q':{
347                                 struct p9_qid *qid =
348                                     va_arg(ap, struct p9_qid *);
349
350                                 errcode = p9pdu_readf(pdu, proto_version, "bdq",
351                                                       &qid->type, &qid->version,
352                                                       &qid->path);
353                         }
354                         break;
355                 case 'S':{
356                                 struct p9_wstat *stbuf =
357                                     va_arg(ap, struct p9_wstat *);
358
359                                 memset(stbuf, 0, sizeof(struct p9_wstat));
360                                 stbuf->n_uid = stbuf->n_muid = INVALID_UID;
361                                 stbuf->n_gid = INVALID_GID;
362
363                                 errcode =
364                                     p9pdu_readf(pdu, proto_version,
365                                                 "wwdQdddqssss?sugu",
366                                                 &stbuf->size, &stbuf->type,
367                                                 &stbuf->dev, &stbuf->qid,
368                                                 &stbuf->mode, &stbuf->atime,
369                                                 &stbuf->mtime, &stbuf->length,
370                                                 &stbuf->name, &stbuf->uid,
371                                                 &stbuf->gid, &stbuf->muid,
372                                                 &stbuf->extension,
373                                                 &stbuf->n_uid, &stbuf->n_gid,
374                                                 &stbuf->n_muid);
375                                 if (errcode)
376                                         p9stat_free(stbuf);
377                         }
378                         break;
379                 case 'D':{
380                                 uint32_t *count = va_arg(ap, uint32_t *);
381                                 void **data = va_arg(ap, void **);
382
383                                 errcode =
384                                     p9pdu_readf(pdu, proto_version, "d", count);
385                                 if (!errcode) {
386                                         *count =
387                                             min_t(uint32_t, *count,
388                                                   pdu->size - pdu->offset);
389                                         *data = &pdu->sdata[pdu->offset];
390                                 }
391                         }
392                         break;
393                 case 'T':{
394                                 uint16_t *nwname = va_arg(ap, uint16_t *);
395                                 char ***wnames = va_arg(ap, char ***);
396
397                                 *wnames = NULL;
398
399                                 errcode = p9pdu_readf(pdu, proto_version,
400                                                                 "w", nwname);
401                                 if (!errcode) {
402                                         *wnames =
403                                             kmalloc_array(*nwname,
404                                                           sizeof(char *),
405                                                           GFP_NOFS);
406                                         if (!*wnames)
407                                                 errcode = -ENOMEM;
408                                         else
409                                                 (*wnames)[0] = NULL;
410                                 }
411
412                                 if (!errcode) {
413                                         int i;
414
415                                         for (i = 0; i < *nwname; i++) {
416                                                 errcode =
417                                                     p9pdu_readf(pdu,
418                                                                 proto_version,
419                                                                 "s",
420                                                                 &(*wnames)[i]);
421                                                 if (errcode) {
422                                                         (*wnames)[i] = NULL;
423                                                         break;
424                                                 }
425                                         }
426                                 }
427
428                                 if (errcode) {
429                                         if (*wnames) {
430                                                 int i;
431
432                                                 for (i = 0; i < *nwname; i++) {
433                                                         if (!(*wnames)[i])
434                                                                 break;
435                                                         kfree((*wnames)[i]);
436                                                 }
437                                                 kfree(*wnames);
438                                                 *wnames = NULL;
439                                         }
440                                 }
441                         }
442                         break;
443                 case 'R':{
444                                 uint16_t *nwqid = va_arg(ap, uint16_t *);
445                                 struct p9_qid **wqids =
446                                     va_arg(ap, struct p9_qid **);
447
448                                 *wqids = NULL;
449
450                                 errcode =
451                                     p9pdu_readf(pdu, proto_version, "w", nwqid);
452                                 if (!errcode) {
453                                         *wqids =
454                                             kmalloc_array(*nwqid,
455                                                           sizeof(struct p9_qid),
456                                                           GFP_NOFS);
457                                         if (*wqids == NULL)
458                                                 errcode = -ENOMEM;
459                                 }
460
461                                 if (!errcode) {
462                                         int i;
463
464                                         for (i = 0; i < *nwqid; i++) {
465                                                 errcode =
466                                                     p9pdu_readf(pdu,
467                                                                 proto_version,
468                                                                 "Q",
469                                                                 &(*wqids)[i]);
470                                                 if (errcode)
471                                                         break;
472                                         }
473                                 }
474
475                                 if (errcode) {
476                                         kfree(*wqids);
477                                         *wqids = NULL;
478                                 }
479                         }
480                         break;
481                 case 'A': {
482                                 struct p9_stat_dotl *stbuf =
483                                     va_arg(ap, struct p9_stat_dotl *);
484
485                                 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
486                                 errcode =
487                                     p9pdu_readf(pdu, proto_version,
488                                         "qQdugqqqqqqqqqqqqqqq",
489                                         &stbuf->st_result_mask,
490                                         &stbuf->qid,
491                                         &stbuf->st_mode,
492                                         &stbuf->st_uid, &stbuf->st_gid,
493                                         &stbuf->st_nlink,
494                                         &stbuf->st_rdev, &stbuf->st_size,
495                                         &stbuf->st_blksize, &stbuf->st_blocks,
496                                         &stbuf->st_atime_sec,
497                                         &stbuf->st_atime_nsec,
498                                         &stbuf->st_mtime_sec,
499                                         &stbuf->st_mtime_nsec,
500                                         &stbuf->st_ctime_sec,
501                                         &stbuf->st_ctime_nsec,
502                                         &stbuf->st_btime_sec,
503                                         &stbuf->st_btime_nsec,
504                                         &stbuf->st_gen,
505                                         &stbuf->st_data_version);
506                         }
507                         break;
508                 case '?':
509                         if ((proto_version != p9_proto_2000u) &&
510                                 (proto_version != p9_proto_2000L))
511                                 return 0;
512                         break;
513                 default:
514                         BUG();
515                         break;
516                 }
517
518                 if (errcode)
519                         break;
520         }
521
522         return errcode;
523 }
524
525 int
526 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
527         va_list ap)
528 {
529         const char *ptr;
530         int errcode = 0;
531
532         for (ptr = fmt; *ptr; ptr++) {
533                 switch (*ptr) {
534                 case 'b':{
535                                 int8_t val = va_arg(ap, int);
536                                 if (pdu_write(pdu, &val, sizeof(val)))
537                                         errcode = -EFAULT;
538                         }
539                         break;
540                 case 'w':{
541                                 __le16 val = cpu_to_le16(va_arg(ap, int));
542                                 if (pdu_write(pdu, &val, sizeof(val)))
543                                         errcode = -EFAULT;
544                         }
545                         break;
546                 case 'd':{
547                                 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
548                                 if (pdu_write(pdu, &val, sizeof(val)))
549                                         errcode = -EFAULT;
550                         }
551                         break;
552                 case 'q':{
553                                 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
554                                 if (pdu_write(pdu, &val, sizeof(val)))
555                                         errcode = -EFAULT;
556                         }
557                         break;
558                 case 's':{
559                                 const char *sptr = va_arg(ap, const char *);
560                                 uint16_t len = 0;
561                                 if (sptr)
562                                         len = min_t(size_t, strlen(sptr),
563                                                                 USHRT_MAX);
564
565                                 errcode = p9pdu_writef(pdu, proto_version,
566                                                                 "w", len);
567                                 if (!errcode && pdu_write(pdu, sptr, len))
568                                         errcode = -EFAULT;
569                         }
570                         break;
571                 case 'u': {
572                                 kuid_t uid = va_arg(ap, kuid_t);
573                                 __le32 val = cpu_to_le32(
574                                                 from_kuid(&init_user_ns, uid));
575                                 if (pdu_write(pdu, &val, sizeof(val)))
576                                         errcode = -EFAULT;
577                         } break;
578                 case 'g': {
579                                 kgid_t gid = va_arg(ap, kgid_t);
580                                 __le32 val = cpu_to_le32(
581                                                 from_kgid(&init_user_ns, gid));
582                                 if (pdu_write(pdu, &val, sizeof(val)))
583                                         errcode = -EFAULT;
584                         } break;
585                 case 'Q':{
586                                 const struct p9_qid *qid =
587                                     va_arg(ap, const struct p9_qid *);
588                                 errcode =
589                                     p9pdu_writef(pdu, proto_version, "bdq",
590                                                  qid->type, qid->version,
591                                                  qid->path);
592                         } break;
593                 case 'S':{
594                                 const struct p9_wstat *stbuf =
595                                     va_arg(ap, const struct p9_wstat *);
596                                 errcode =
597                                     p9pdu_writef(pdu, proto_version,
598                                                  "wwdQdddqssss?sugu",
599                                                  stbuf->size, stbuf->type,
600                                                  stbuf->dev, &stbuf->qid,
601                                                  stbuf->mode, stbuf->atime,
602                                                  stbuf->mtime, stbuf->length,
603                                                  stbuf->name, stbuf->uid,
604                                                  stbuf->gid, stbuf->muid,
605                                                  stbuf->extension, stbuf->n_uid,
606                                                  stbuf->n_gid, stbuf->n_muid);
607                         } break;
608                 case 'V':{
609                                 uint32_t count = va_arg(ap, uint32_t);
610                                 struct iov_iter *from =
611                                                 va_arg(ap, struct iov_iter *);
612                                 errcode = p9pdu_writef(pdu, proto_version, "d",
613                                                                         count);
614                                 if (!errcode && pdu_write_u(pdu, from, count))
615                                         errcode = -EFAULT;
616                         }
617                         break;
618                 case 'T':{
619                                 uint16_t nwname = va_arg(ap, int);
620                                 const char **wnames = va_arg(ap, const char **);
621
622                                 errcode = p9pdu_writef(pdu, proto_version, "w",
623                                                                         nwname);
624                                 if (!errcode) {
625                                         int i;
626
627                                         for (i = 0; i < nwname; i++) {
628                                                 errcode =
629                                                     p9pdu_writef(pdu,
630                                                                 proto_version,
631                                                                  "s",
632                                                                  wnames[i]);
633                                                 if (errcode)
634                                                         break;
635                                         }
636                                 }
637                         }
638                         break;
639                 case 'R':{
640                                 uint16_t nwqid = va_arg(ap, int);
641                                 struct p9_qid *wqids =
642                                     va_arg(ap, struct p9_qid *);
643
644                                 errcode = p9pdu_writef(pdu, proto_version, "w",
645                                                                         nwqid);
646                                 if (!errcode) {
647                                         int i;
648
649                                         for (i = 0; i < nwqid; i++) {
650                                                 errcode =
651                                                     p9pdu_writef(pdu,
652                                                                 proto_version,
653                                                                  "Q",
654                                                                  &wqids[i]);
655                                                 if (errcode)
656                                                         break;
657                                         }
658                                 }
659                         }
660                         break;
661                 case 'I':{
662                                 struct p9_iattr_dotl *p9attr = va_arg(ap,
663                                                         struct p9_iattr_dotl *);
664
665                                 errcode = p9pdu_writef(pdu, proto_version,
666                                                         "ddugqqqqq",
667                                                         p9attr->valid,
668                                                         p9attr->mode,
669                                                         p9attr->uid,
670                                                         p9attr->gid,
671                                                         p9attr->size,
672                                                         p9attr->atime_sec,
673                                                         p9attr->atime_nsec,
674                                                         p9attr->mtime_sec,
675                                                         p9attr->mtime_nsec);
676                         }
677                         break;
678                 case '?':
679                         if ((proto_version != p9_proto_2000u) &&
680                                 (proto_version != p9_proto_2000L))
681                                 return 0;
682                         break;
683                 default:
684                         BUG();
685                         break;
686                 }
687
688                 if (errcode)
689                         break;
690         }
691
692         return errcode;
693 }
694
695 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
696 {
697         va_list ap;
698         int ret;
699
700         va_start(ap, fmt);
701         ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
702         va_end(ap);
703
704         return ret;
705 }
706
707 static int
708 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
709 {
710         va_list ap;
711         int ret;
712
713         va_start(ap, fmt);
714         ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
715         va_end(ap);
716
717         return ret;
718 }
719
720 int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
721 {
722         struct p9_fcall fake_pdu;
723         int ret;
724
725         fake_pdu.size = len;
726         fake_pdu.capacity = len;
727         fake_pdu.sdata = buf;
728         fake_pdu.offset = 0;
729
730         ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);
731         if (ret) {
732                 p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
733                 trace_9p_protocol_dump(clnt, &fake_pdu);
734                 return ret;
735         }
736
737         return fake_pdu.offset;
738 }
739 EXPORT_SYMBOL(p9stat_read);
740
741 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
742 {
743         pdu->id = type;
744         return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
745 }
746
747 int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)
748 {
749         int size = pdu->size;
750         int err;
751
752         pdu->size = 0;
753         err = p9pdu_writef(pdu, 0, "d", size);
754         pdu->size = size;
755
756         trace_9p_protocol_dump(clnt, pdu);
757         p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n",
758                  pdu->size, pdu->id, pdu->tag);
759
760         return err;
761 }
762
763 void p9pdu_reset(struct p9_fcall *pdu)
764 {
765         pdu->offset = 0;
766         pdu->size = 0;
767 }
768
769 int p9dirent_read(struct p9_client *clnt, char *buf, int len,
770                   struct p9_dirent *dirent)
771 {
772         struct p9_fcall fake_pdu;
773         int ret;
774         char *nameptr;
775
776         fake_pdu.size = len;
777         fake_pdu.capacity = len;
778         fake_pdu.sdata = buf;
779         fake_pdu.offset = 0;
780
781         ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid,
782                           &dirent->d_off, &dirent->d_type, &nameptr);
783         if (ret) {
784                 p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
785                 trace_9p_protocol_dump(clnt, &fake_pdu);
786                 return ret;
787         }
788
789         ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
790         if (ret < 0) {
791                 p9_debug(P9_DEBUG_ERROR,
792                          "On the wire dirent name too long: %s\n",
793                          nameptr);
794                 kfree(nameptr);
795                 return ret;
796         }
797         kfree(nameptr);
798
799         return fake_pdu.offset;
800 }
801 EXPORT_SYMBOL(p9dirent_read);