9p: Reduce object size with CONFIG_NET_9P_DEBUG
[linux-3.10.git] / net / 9p / protocol.c
1 /*
2  * net/9p/protocol.c
3  *
4  * 9P Protocol Support Code
5  *
6  *  Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
7  *
8  *  Base on code from Anthony Liguori <aliguori@us.ibm.com>
9  *  Copyright (C) 2008 by IBM, Corp.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License version 2
13  *  as published by the Free Software Foundation.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to:
22  *  Free Software Foundation
23  *  51 Franklin Street, Fifth Floor
24  *  Boston, MA  02111-1301  USA
25  *
26  */
27
28 #include <linux/module.h>
29 #include <linux/errno.h>
30 #include <linux/kernel.h>
31 #include <linux/uaccess.h>
32 #include <linux/slab.h>
33 #include <linux/sched.h>
34 #include <linux/stddef.h>
35 #include <linux/types.h>
36 #include <net/9p/9p.h>
37 #include <net/9p/client.h>
38 #include "protocol.h"
39
40 #include <trace/events/9p.h>
41
42 static int
43 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
44
45 void p9stat_free(struct p9_wstat *stbuf)
46 {
47         kfree(stbuf->name);
48         kfree(stbuf->uid);
49         kfree(stbuf->gid);
50         kfree(stbuf->muid);
51         kfree(stbuf->extension);
52 }
53 EXPORT_SYMBOL(p9stat_free);
54
55 size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
56 {
57         size_t len = min(pdu->size - pdu->offset, size);
58         memcpy(data, &pdu->sdata[pdu->offset], len);
59         pdu->offset += len;
60         return size - len;
61 }
62
63 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
64 {
65         size_t len = min(pdu->capacity - pdu->size, size);
66         memcpy(&pdu->sdata[pdu->size], data, len);
67         pdu->size += len;
68         return size - len;
69 }
70
71 static size_t
72 pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
73 {
74         size_t len = min(pdu->capacity - pdu->size, size);
75         if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
76                 len = 0;
77
78         pdu->size += len;
79         return size - len;
80 }
81
82 /*
83         b - int8_t
84         w - int16_t
85         d - int32_t
86         q - int64_t
87         s - string
88         S - stat
89         Q - qid
90         D - data blob (int32_t size followed by void *, results are not freed)
91         T - array of strings (int16_t count, followed by strings)
92         R - array of qids (int16_t count, followed by qids)
93         A - stat for 9p2000.L (p9_stat_dotl)
94         ? - if optional = 1, continue parsing
95 */
96
97 static int
98 p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
99         va_list ap)
100 {
101         const char *ptr;
102         int errcode = 0;
103
104         for (ptr = fmt; *ptr; ptr++) {
105                 switch (*ptr) {
106                 case 'b':{
107                                 int8_t *val = va_arg(ap, int8_t *);
108                                 if (pdu_read(pdu, val, sizeof(*val))) {
109                                         errcode = -EFAULT;
110                                         break;
111                                 }
112                         }
113                         break;
114                 case 'w':{
115                                 int16_t *val = va_arg(ap, int16_t *);
116                                 __le16 le_val;
117                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
118                                         errcode = -EFAULT;
119                                         break;
120                                 }
121                                 *val = le16_to_cpu(le_val);
122                         }
123                         break;
124                 case 'd':{
125                                 int32_t *val = va_arg(ap, int32_t *);
126                                 __le32 le_val;
127                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
128                                         errcode = -EFAULT;
129                                         break;
130                                 }
131                                 *val = le32_to_cpu(le_val);
132                         }
133                         break;
134                 case 'q':{
135                                 int64_t *val = va_arg(ap, int64_t *);
136                                 __le64 le_val;
137                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
138                                         errcode = -EFAULT;
139                                         break;
140                                 }
141                                 *val = le64_to_cpu(le_val);
142                         }
143                         break;
144                 case 's':{
145                                 char **sptr = va_arg(ap, char **);
146                                 uint16_t len;
147
148                                 errcode = p9pdu_readf(pdu, proto_version,
149                                                                 "w", &len);
150                                 if (errcode)
151                                         break;
152
153                                 *sptr = kmalloc(len + 1, GFP_NOFS);
154                                 if (*sptr == NULL) {
155                                         errcode = -EFAULT;
156                                         break;
157                                 }
158                                 if (pdu_read(pdu, *sptr, len)) {
159                                         errcode = -EFAULT;
160                                         kfree(*sptr);
161                                         *sptr = NULL;
162                                 } else
163                                         (*sptr)[len] = 0;
164                         }
165                         break;
166                 case 'Q':{
167                                 struct p9_qid *qid =
168                                     va_arg(ap, struct p9_qid *);
169
170                                 errcode = p9pdu_readf(pdu, proto_version, "bdq",
171                                                       &qid->type, &qid->version,
172                                                       &qid->path);
173                         }
174                         break;
175                 case 'S':{
176                                 struct p9_wstat *stbuf =
177                                     va_arg(ap, struct p9_wstat *);
178
179                                 memset(stbuf, 0, sizeof(struct p9_wstat));
180                                 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
181                                                                         -1;
182                                 errcode =
183                                     p9pdu_readf(pdu, proto_version,
184                                                 "wwdQdddqssss?sddd",
185                                                 &stbuf->size, &stbuf->type,
186                                                 &stbuf->dev, &stbuf->qid,
187                                                 &stbuf->mode, &stbuf->atime,
188                                                 &stbuf->mtime, &stbuf->length,
189                                                 &stbuf->name, &stbuf->uid,
190                                                 &stbuf->gid, &stbuf->muid,
191                                                 &stbuf->extension,
192                                                 &stbuf->n_uid, &stbuf->n_gid,
193                                                 &stbuf->n_muid);
194                                 if (errcode)
195                                         p9stat_free(stbuf);
196                         }
197                         break;
198                 case 'D':{
199                                 uint32_t *count = va_arg(ap, uint32_t *);
200                                 void **data = va_arg(ap, void **);
201
202                                 errcode =
203                                     p9pdu_readf(pdu, proto_version, "d", count);
204                                 if (!errcode) {
205                                         *count =
206                                             min_t(uint32_t, *count,
207                                                   pdu->size - pdu->offset);
208                                         *data = &pdu->sdata[pdu->offset];
209                                 }
210                         }
211                         break;
212                 case 'T':{
213                                 uint16_t *nwname = va_arg(ap, uint16_t *);
214                                 char ***wnames = va_arg(ap, char ***);
215
216                                 errcode = p9pdu_readf(pdu, proto_version,
217                                                                 "w", nwname);
218                                 if (!errcode) {
219                                         *wnames =
220                                             kmalloc(sizeof(char *) * *nwname,
221                                                     GFP_NOFS);
222                                         if (!*wnames)
223                                                 errcode = -ENOMEM;
224                                 }
225
226                                 if (!errcode) {
227                                         int i;
228
229                                         for (i = 0; i < *nwname; i++) {
230                                                 errcode =
231                                                     p9pdu_readf(pdu,
232                                                                 proto_version,
233                                                                 "s",
234                                                                 &(*wnames)[i]);
235                                                 if (errcode)
236                                                         break;
237                                         }
238                                 }
239
240                                 if (errcode) {
241                                         if (*wnames) {
242                                                 int i;
243
244                                                 for (i = 0; i < *nwname; i++)
245                                                         kfree((*wnames)[i]);
246                                         }
247                                         kfree(*wnames);
248                                         *wnames = NULL;
249                                 }
250                         }
251                         break;
252                 case 'R':{
253                                 int16_t *nwqid = va_arg(ap, int16_t *);
254                                 struct p9_qid **wqids =
255                                     va_arg(ap, struct p9_qid **);
256
257                                 *wqids = NULL;
258
259                                 errcode =
260                                     p9pdu_readf(pdu, proto_version, "w", nwqid);
261                                 if (!errcode) {
262                                         *wqids =
263                                             kmalloc(*nwqid *
264                                                     sizeof(struct p9_qid),
265                                                     GFP_NOFS);
266                                         if (*wqids == NULL)
267                                                 errcode = -ENOMEM;
268                                 }
269
270                                 if (!errcode) {
271                                         int i;
272
273                                         for (i = 0; i < *nwqid; i++) {
274                                                 errcode =
275                                                     p9pdu_readf(pdu,
276                                                                 proto_version,
277                                                                 "Q",
278                                                                 &(*wqids)[i]);
279                                                 if (errcode)
280                                                         break;
281                                         }
282                                 }
283
284                                 if (errcode) {
285                                         kfree(*wqids);
286                                         *wqids = NULL;
287                                 }
288                         }
289                         break;
290                 case 'A': {
291                                 struct p9_stat_dotl *stbuf =
292                                     va_arg(ap, struct p9_stat_dotl *);
293
294                                 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
295                                 errcode =
296                                     p9pdu_readf(pdu, proto_version,
297                                         "qQdddqqqqqqqqqqqqqqq",
298                                         &stbuf->st_result_mask,
299                                         &stbuf->qid,
300                                         &stbuf->st_mode,
301                                         &stbuf->st_uid, &stbuf->st_gid,
302                                         &stbuf->st_nlink,
303                                         &stbuf->st_rdev, &stbuf->st_size,
304                                         &stbuf->st_blksize, &stbuf->st_blocks,
305                                         &stbuf->st_atime_sec,
306                                         &stbuf->st_atime_nsec,
307                                         &stbuf->st_mtime_sec,
308                                         &stbuf->st_mtime_nsec,
309                                         &stbuf->st_ctime_sec,
310                                         &stbuf->st_ctime_nsec,
311                                         &stbuf->st_btime_sec,
312                                         &stbuf->st_btime_nsec,
313                                         &stbuf->st_gen,
314                                         &stbuf->st_data_version);
315                         }
316                         break;
317                 case '?':
318                         if ((proto_version != p9_proto_2000u) &&
319                                 (proto_version != p9_proto_2000L))
320                                 return 0;
321                         break;
322                 default:
323                         BUG();
324                         break;
325                 }
326
327                 if (errcode)
328                         break;
329         }
330
331         return errcode;
332 }
333
334 int
335 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
336         va_list ap)
337 {
338         const char *ptr;
339         int errcode = 0;
340
341         for (ptr = fmt; *ptr; ptr++) {
342                 switch (*ptr) {
343                 case 'b':{
344                                 int8_t val = va_arg(ap, int);
345                                 if (pdu_write(pdu, &val, sizeof(val)))
346                                         errcode = -EFAULT;
347                         }
348                         break;
349                 case 'w':{
350                                 __le16 val = cpu_to_le16(va_arg(ap, int));
351                                 if (pdu_write(pdu, &val, sizeof(val)))
352                                         errcode = -EFAULT;
353                         }
354                         break;
355                 case 'd':{
356                                 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
357                                 if (pdu_write(pdu, &val, sizeof(val)))
358                                         errcode = -EFAULT;
359                         }
360                         break;
361                 case 'q':{
362                                 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
363                                 if (pdu_write(pdu, &val, sizeof(val)))
364                                         errcode = -EFAULT;
365                         }
366                         break;
367                 case 's':{
368                                 const char *sptr = va_arg(ap, const char *);
369                                 uint16_t len = 0;
370                                 if (sptr)
371                                         len = min_t(uint16_t, strlen(sptr),
372                                                                 USHRT_MAX);
373
374                                 errcode = p9pdu_writef(pdu, proto_version,
375                                                                 "w", len);
376                                 if (!errcode && pdu_write(pdu, sptr, len))
377                                         errcode = -EFAULT;
378                         }
379                         break;
380                 case 'Q':{
381                                 const struct p9_qid *qid =
382                                     va_arg(ap, const struct p9_qid *);
383                                 errcode =
384                                     p9pdu_writef(pdu, proto_version, "bdq",
385                                                  qid->type, qid->version,
386                                                  qid->path);
387                         } break;
388                 case 'S':{
389                                 const struct p9_wstat *stbuf =
390                                     va_arg(ap, const struct p9_wstat *);
391                                 errcode =
392                                     p9pdu_writef(pdu, proto_version,
393                                                  "wwdQdddqssss?sddd",
394                                                  stbuf->size, stbuf->type,
395                                                  stbuf->dev, &stbuf->qid,
396                                                  stbuf->mode, stbuf->atime,
397                                                  stbuf->mtime, stbuf->length,
398                                                  stbuf->name, stbuf->uid,
399                                                  stbuf->gid, stbuf->muid,
400                                                  stbuf->extension, stbuf->n_uid,
401                                                  stbuf->n_gid, stbuf->n_muid);
402                         } break;
403                 case 'D':{
404                                 uint32_t count = va_arg(ap, uint32_t);
405                                 const void *data = va_arg(ap, const void *);
406
407                                 errcode = p9pdu_writef(pdu, proto_version, "d",
408                                                                         count);
409                                 if (!errcode && pdu_write(pdu, data, count))
410                                         errcode = -EFAULT;
411                         }
412                         break;
413                 case 'U':{
414                                 int32_t count = va_arg(ap, int32_t);
415                                 const char __user *udata =
416                                                 va_arg(ap, const void __user *);
417                                 errcode = p9pdu_writef(pdu, proto_version, "d",
418                                                                         count);
419                                 if (!errcode && pdu_write_u(pdu, udata, count))
420                                         errcode = -EFAULT;
421                         }
422                         break;
423                 case 'T':{
424                                 uint16_t nwname = va_arg(ap, int);
425                                 const char **wnames = va_arg(ap, const char **);
426
427                                 errcode = p9pdu_writef(pdu, proto_version, "w",
428                                                                         nwname);
429                                 if (!errcode) {
430                                         int i;
431
432                                         for (i = 0; i < nwname; i++) {
433                                                 errcode =
434                                                     p9pdu_writef(pdu,
435                                                                 proto_version,
436                                                                  "s",
437                                                                  wnames[i]);
438                                                 if (errcode)
439                                                         break;
440                                         }
441                                 }
442                         }
443                         break;
444                 case 'R':{
445                                 int16_t nwqid = va_arg(ap, int);
446                                 struct p9_qid *wqids =
447                                     va_arg(ap, struct p9_qid *);
448
449                                 errcode = p9pdu_writef(pdu, proto_version, "w",
450                                                                         nwqid);
451                                 if (!errcode) {
452                                         int i;
453
454                                         for (i = 0; i < nwqid; i++) {
455                                                 errcode =
456                                                     p9pdu_writef(pdu,
457                                                                 proto_version,
458                                                                  "Q",
459                                                                  &wqids[i]);
460                                                 if (errcode)
461                                                         break;
462                                         }
463                                 }
464                         }
465                         break;
466                 case 'I':{
467                                 struct p9_iattr_dotl *p9attr = va_arg(ap,
468                                                         struct p9_iattr_dotl *);
469
470                                 errcode = p9pdu_writef(pdu, proto_version,
471                                                         "ddddqqqqq",
472                                                         p9attr->valid,
473                                                         p9attr->mode,
474                                                         p9attr->uid,
475                                                         p9attr->gid,
476                                                         p9attr->size,
477                                                         p9attr->atime_sec,
478                                                         p9attr->atime_nsec,
479                                                         p9attr->mtime_sec,
480                                                         p9attr->mtime_nsec);
481                         }
482                         break;
483                 case '?':
484                         if ((proto_version != p9_proto_2000u) &&
485                                 (proto_version != p9_proto_2000L))
486                                 return 0;
487                         break;
488                 default:
489                         BUG();
490                         break;
491                 }
492
493                 if (errcode)
494                         break;
495         }
496
497         return errcode;
498 }
499
500 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
501 {
502         va_list ap;
503         int ret;
504
505         va_start(ap, fmt);
506         ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
507         va_end(ap);
508
509         return ret;
510 }
511
512 static int
513 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
514 {
515         va_list ap;
516         int ret;
517
518         va_start(ap, fmt);
519         ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
520         va_end(ap);
521
522         return ret;
523 }
524
525 int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
526 {
527         struct p9_fcall fake_pdu;
528         int ret;
529
530         fake_pdu.size = len;
531         fake_pdu.capacity = len;
532         fake_pdu.sdata = buf;
533         fake_pdu.offset = 0;
534
535         ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);
536         if (ret) {
537                 p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
538                 trace_9p_protocol_dump(clnt, &fake_pdu);
539         }
540
541         return ret;
542 }
543 EXPORT_SYMBOL(p9stat_read);
544
545 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
546 {
547         pdu->id = type;
548         return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
549 }
550
551 int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)
552 {
553         int size = pdu->size;
554         int err;
555
556         pdu->size = 0;
557         err = p9pdu_writef(pdu, 0, "d", size);
558         pdu->size = size;
559
560         trace_9p_protocol_dump(clnt, pdu);
561         p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n",
562                  pdu->size, pdu->id, pdu->tag);
563
564         return err;
565 }
566
567 void p9pdu_reset(struct p9_fcall *pdu)
568 {
569         pdu->offset = 0;
570         pdu->size = 0;
571 }
572
573 int p9dirent_read(struct p9_client *clnt, char *buf, int len,
574                   struct p9_dirent *dirent)
575 {
576         struct p9_fcall fake_pdu;
577         int ret;
578         char *nameptr;
579
580         fake_pdu.size = len;
581         fake_pdu.capacity = len;
582         fake_pdu.sdata = buf;
583         fake_pdu.offset = 0;
584
585         ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid,
586                           &dirent->d_off, &dirent->d_type, &nameptr);
587         if (ret) {
588                 p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
589                 trace_9p_protocol_dump(clnt, &fake_pdu);
590                 goto out;
591         }
592
593         strcpy(dirent->d_name, nameptr);
594         kfree(nameptr);
595
596 out:
597         return fake_pdu.offset;
598 }
599 EXPORT_SYMBOL(p9dirent_read);