blob: b7d4e8aa5383e7e2022cdcdd92205d0b634fe06e [file] [log] [blame]
Eric Van Hensbergenace51c42008-10-13 20:40:27 -05001/*
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>
Thiago Farina01b0c5c2010-12-04 15:22:46 +000030#include <linux/kernel.h>
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -050031#include <linux/uaccess.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Eric Van Hensbergene7f4b8f2008-10-17 16:20:07 -050033#include <linux/sched.h>
Thiago Farina01b0c5c2010-12-04 15:22:46 +000034#include <linux/stddef.h>
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -080035#include <linux/types.h>
Eric Van Hensbergenace51c42008-10-13 20:40:27 -050036#include <net/9p/9p.h>
37#include <net/9p/client.h>
38#include "protocol.h"
39
Eric Van Hensbergenace51c42008-10-13 20:40:27 -050040static int
Sripathi Kodi342fee12010-03-05 18:50:14 +000041p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -050042
Eric Van Hensbergen0b15a3a2008-10-22 18:47:40 -050043#ifdef CONFIG_NET_9P_DEBUG
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -050044void
45p9pdu_dump(int way, struct p9_fcall *pdu)
46{
Eric Van Hensbergene660a822011-06-19 16:38:21 -050047 int len = pdu->size;
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -050048
Eric Van Hensbergene660a822011-06-19 16:38:21 -050049 if ((p9_debug_level & P9_DEBUG_VPKT) != P9_DEBUG_VPKT) {
50 if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) {
51 if (len > 32)
52 len = 32;
53 } else {
54 /* shouldn't happen */
55 return;
56 }
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -050057 }
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -050058
59 if (way)
Eric Van Hensbergene660a822011-06-19 16:38:21 -050060 print_hex_dump_bytes("[9P] ", DUMP_PREFIX_OFFSET, pdu->sdata,
61 len);
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -050062 else
Eric Van Hensbergene660a822011-06-19 16:38:21 -050063 print_hex_dump_bytes("]9P[ ", DUMP_PREFIX_OFFSET, pdu->sdata,
64 len);
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -050065}
Eric Van Hensbergen0b15a3a2008-10-22 18:47:40 -050066#else
67void
68p9pdu_dump(int way, struct p9_fcall *pdu)
69{
70}
71#endif
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -050072EXPORT_SYMBOL(p9pdu_dump);
73
Eric Van Hensbergenace51c42008-10-13 20:40:27 -050074void p9stat_free(struct p9_wstat *stbuf)
75{
76 kfree(stbuf->name);
77 kfree(stbuf->uid);
78 kfree(stbuf->gid);
79 kfree(stbuf->muid);
80 kfree(stbuf->extension);
81}
82EXPORT_SYMBOL(p9stat_free);
83
Aneesh Kumar K.Vabfa0342011-08-16 10:50:10 +053084size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
Eric Van Hensbergenace51c42008-10-13 20:40:27 -050085{
Thiago Farina01b0c5c2010-12-04 15:22:46 +000086 size_t len = min(pdu->size - pdu->offset, size);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -050087 memcpy(data, &pdu->sdata[pdu->offset], len);
88 pdu->offset += len;
89 return size - len;
90}
91
92static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
93{
Thiago Farina01b0c5c2010-12-04 15:22:46 +000094 size_t len = min(pdu->capacity - pdu->size, size);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -050095 memcpy(&pdu->sdata[pdu->size], data, len);
96 pdu->size += len;
97 return size - len;
98}
99
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500100static size_t
101pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
102{
Thiago Farina01b0c5c2010-12-04 15:22:46 +0000103 size_t len = min(pdu->capacity - pdu->size, size);
Aneesh Kumar K.V7b3bb3f2010-10-19 09:17:02 +0530104 if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
105 len = 0;
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500106
107 pdu->size += len;
108 return size - len;
109}
110
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500111/*
112 b - int8_t
113 w - int16_t
114 d - int32_t
115 q - int64_t
116 s - string
117 S - stat
118 Q - qid
119 D - data blob (int32_t size followed by void *, results are not freed)
120 T - array of strings (int16_t count, followed by strings)
121 R - array of qids (int16_t count, followed by qids)
Sripathi Kodif0853122010-07-12 20:07:23 +0530122 A - stat for 9p2000.L (p9_stat_dotl)
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500123 ? - if optional = 1, continue parsing
124*/
125
126static int
Sripathi Kodi342fee12010-03-05 18:50:14 +0000127p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
128 va_list ap)
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500129{
130 const char *ptr;
131 int errcode = 0;
132
133 for (ptr = fmt; *ptr; ptr++) {
134 switch (*ptr) {
135 case 'b':{
136 int8_t *val = va_arg(ap, int8_t *);
137 if (pdu_read(pdu, val, sizeof(*val))) {
138 errcode = -EFAULT;
139 break;
140 }
141 }
142 break;
143 case 'w':{
144 int16_t *val = va_arg(ap, int16_t *);
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -0800145 __le16 le_val;
146 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500147 errcode = -EFAULT;
148 break;
149 }
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -0800150 *val = le16_to_cpu(le_val);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500151 }
152 break;
153 case 'd':{
154 int32_t *val = va_arg(ap, int32_t *);
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -0800155 __le32 le_val;
156 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500157 errcode = -EFAULT;
158 break;
159 }
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -0800160 *val = le32_to_cpu(le_val);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500161 }
162 break;
163 case 'q':{
164 int64_t *val = va_arg(ap, int64_t *);
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -0800165 __le64 le_val;
166 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500167 errcode = -EFAULT;
168 break;
169 }
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -0800170 *val = le64_to_cpu(le_val);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500171 }
172 break;
173 case 's':{
Eric Van Hensbergene45c5402008-10-22 18:54:47 -0500174 char **sptr = va_arg(ap, char **);
M. Mohan Kumar219fd582011-01-10 14:23:53 -0600175 uint16_t len;
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500176
Sripathi Kodi342fee12010-03-05 18:50:14 +0000177 errcode = p9pdu_readf(pdu, proto_version,
178 "w", &len);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500179 if (errcode)
180 break;
181
Aneesh Kumar K.Veeff66e2011-03-08 16:39:47 +0530182 *sptr = kmalloc(len + 1, GFP_NOFS);
Eric Van Hensbergene45c5402008-10-22 18:54:47 -0500183 if (*sptr == NULL) {
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500184 errcode = -EFAULT;
185 break;
186 }
M. Mohan Kumar219fd582011-01-10 14:23:53 -0600187 if (pdu_read(pdu, *sptr, len)) {
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500188 errcode = -EFAULT;
Eric Van Hensbergene45c5402008-10-22 18:54:47 -0500189 kfree(*sptr);
190 *sptr = NULL;
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500191 } else
M. Mohan Kumar219fd582011-01-10 14:23:53 -0600192 (*sptr)[len] = 0;
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500193 }
194 break;
195 case 'Q':{
196 struct p9_qid *qid =
197 va_arg(ap, struct p9_qid *);
198
Sripathi Kodi342fee12010-03-05 18:50:14 +0000199 errcode = p9pdu_readf(pdu, proto_version, "bdq",
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500200 &qid->type, &qid->version,
201 &qid->path);
202 }
203 break;
204 case 'S':{
205 struct p9_wstat *stbuf =
206 va_arg(ap, struct p9_wstat *);
207
Eric Van Hensbergenf0a0ac22008-10-17 12:45:23 -0500208 memset(stbuf, 0, sizeof(struct p9_wstat));
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500209 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
Eric Van Hensbergenf0a0ac22008-10-17 12:45:23 -0500210 -1;
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500211 errcode =
Sripathi Kodi342fee12010-03-05 18:50:14 +0000212 p9pdu_readf(pdu, proto_version,
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500213 "wwdQdddqssss?sddd",
214 &stbuf->size, &stbuf->type,
215 &stbuf->dev, &stbuf->qid,
216 &stbuf->mode, &stbuf->atime,
217 &stbuf->mtime, &stbuf->length,
218 &stbuf->name, &stbuf->uid,
219 &stbuf->gid, &stbuf->muid,
220 &stbuf->extension,
221 &stbuf->n_uid, &stbuf->n_gid,
222 &stbuf->n_muid);
223 if (errcode)
224 p9stat_free(stbuf);
225 }
226 break;
227 case 'D':{
M. Mohan Kumar219fd582011-01-10 14:23:53 -0600228 uint32_t *count = va_arg(ap, uint32_t *);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500229 void **data = va_arg(ap, void **);
230
231 errcode =
Sripathi Kodi342fee12010-03-05 18:50:14 +0000232 p9pdu_readf(pdu, proto_version, "d", count);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500233 if (!errcode) {
234 *count =
M. Mohan Kumar219fd582011-01-10 14:23:53 -0600235 min_t(uint32_t, *count,
Thiago Farina01b0c5c2010-12-04 15:22:46 +0000236 pdu->size - pdu->offset);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500237 *data = &pdu->sdata[pdu->offset];
238 }
239 }
240 break;
241 case 'T':{
Harsh Prateek Borab76225e2011-03-31 15:49:39 +0530242 uint16_t *nwname = va_arg(ap, uint16_t *);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500243 char ***wnames = va_arg(ap, char ***);
244
Sripathi Kodi342fee12010-03-05 18:50:14 +0000245 errcode = p9pdu_readf(pdu, proto_version,
246 "w", nwname);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500247 if (!errcode) {
248 *wnames =
249 kmalloc(sizeof(char *) * *nwname,
Aneesh Kumar K.Veeff66e2011-03-08 16:39:47 +0530250 GFP_NOFS);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500251 if (!*wnames)
252 errcode = -ENOMEM;
253 }
254
255 if (!errcode) {
256 int i;
257
258 for (i = 0; i < *nwname; i++) {
259 errcode =
Sripathi Kodi342fee12010-03-05 18:50:14 +0000260 p9pdu_readf(pdu,
261 proto_version,
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500262 "s",
263 &(*wnames)[i]);
264 if (errcode)
265 break;
266 }
267 }
268
269 if (errcode) {
270 if (*wnames) {
271 int i;
272
273 for (i = 0; i < *nwname; i++)
274 kfree((*wnames)[i]);
275 }
276 kfree(*wnames);
277 *wnames = NULL;
278 }
279 }
280 break;
281 case 'R':{
282 int16_t *nwqid = va_arg(ap, int16_t *);
283 struct p9_qid **wqids =
284 va_arg(ap, struct p9_qid **);
285
286 *wqids = NULL;
287
288 errcode =
Sripathi Kodi342fee12010-03-05 18:50:14 +0000289 p9pdu_readf(pdu, proto_version, "w", nwqid);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500290 if (!errcode) {
291 *wqids =
292 kmalloc(*nwqid *
293 sizeof(struct p9_qid),
Aneesh Kumar K.Veeff66e2011-03-08 16:39:47 +0530294 GFP_NOFS);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500295 if (*wqids == NULL)
296 errcode = -ENOMEM;
297 }
298
299 if (!errcode) {
300 int i;
301
302 for (i = 0; i < *nwqid; i++) {
303 errcode =
Sripathi Kodi342fee12010-03-05 18:50:14 +0000304 p9pdu_readf(pdu,
305 proto_version,
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500306 "Q",
307 &(*wqids)[i]);
308 if (errcode)
309 break;
310 }
311 }
312
313 if (errcode) {
314 kfree(*wqids);
315 *wqids = NULL;
316 }
317 }
318 break;
Sripathi Kodif0853122010-07-12 20:07:23 +0530319 case 'A': {
320 struct p9_stat_dotl *stbuf =
321 va_arg(ap, struct p9_stat_dotl *);
322
323 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
324 errcode =
325 p9pdu_readf(pdu, proto_version,
326 "qQdddqqqqqqqqqqqqqqq",
327 &stbuf->st_result_mask,
328 &stbuf->qid,
329 &stbuf->st_mode,
330 &stbuf->st_uid, &stbuf->st_gid,
331 &stbuf->st_nlink,
332 &stbuf->st_rdev, &stbuf->st_size,
333 &stbuf->st_blksize, &stbuf->st_blocks,
334 &stbuf->st_atime_sec,
335 &stbuf->st_atime_nsec,
336 &stbuf->st_mtime_sec,
337 &stbuf->st_mtime_nsec,
338 &stbuf->st_ctime_sec,
339 &stbuf->st_ctime_nsec,
340 &stbuf->st_btime_sec,
341 &stbuf->st_btime_nsec,
342 &stbuf->st_gen,
343 &stbuf->st_data_version);
344 }
345 break;
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500346 case '?':
Sripathi Kodic56e4ac2010-03-25 12:40:35 +0000347 if ((proto_version != p9_proto_2000u) &&
348 (proto_version != p9_proto_2000L))
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500349 return 0;
350 break;
351 default:
352 BUG();
353 break;
354 }
355
356 if (errcode)
357 break;
358 }
359
360 return errcode;
361}
362
363int
Sripathi Kodi342fee12010-03-05 18:50:14 +0000364p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
365 va_list ap)
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500366{
367 const char *ptr;
368 int errcode = 0;
369
370 for (ptr = fmt; *ptr; ptr++) {
371 switch (*ptr) {
372 case 'b':{
373 int8_t val = va_arg(ap, int);
374 if (pdu_write(pdu, &val, sizeof(val)))
375 errcode = -EFAULT;
376 }
377 break;
378 case 'w':{
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -0800379 __le16 val = cpu_to_le16(va_arg(ap, int));
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500380 if (pdu_write(pdu, &val, sizeof(val)))
381 errcode = -EFAULT;
382 }
383 break;
384 case 'd':{
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -0800385 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500386 if (pdu_write(pdu, &val, sizeof(val)))
387 errcode = -EFAULT;
388 }
389 break;
390 case 'q':{
Eric Van Hensbergenbeeebc92009-02-06 22:07:41 -0800391 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500392 if (pdu_write(pdu, &val, sizeof(val)))
393 errcode = -EFAULT;
394 }
395 break;
396 case 's':{
Eric Van Hensbergene45c5402008-10-22 18:54:47 -0500397 const char *sptr = va_arg(ap, const char *);
M. Mohan Kumar219fd582011-01-10 14:23:53 -0600398 uint16_t len = 0;
Eric Van Hensbergene45c5402008-10-22 18:54:47 -0500399 if (sptr)
M. Mohan Kumar219fd582011-01-10 14:23:53 -0600400 len = min_t(uint16_t, strlen(sptr),
401 USHRT_MAX);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500402
Sripathi Kodi342fee12010-03-05 18:50:14 +0000403 errcode = p9pdu_writef(pdu, proto_version,
404 "w", len);
Eric Van Hensbergene45c5402008-10-22 18:54:47 -0500405 if (!errcode && pdu_write(pdu, sptr, len))
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500406 errcode = -EFAULT;
407 }
408 break;
409 case 'Q':{
410 const struct p9_qid *qid =
411 va_arg(ap, const struct p9_qid *);
412 errcode =
Sripathi Kodi342fee12010-03-05 18:50:14 +0000413 p9pdu_writef(pdu, proto_version, "bdq",
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500414 qid->type, qid->version,
415 qid->path);
416 } break;
417 case 'S':{
418 const struct p9_wstat *stbuf =
419 va_arg(ap, const struct p9_wstat *);
420 errcode =
Sripathi Kodi342fee12010-03-05 18:50:14 +0000421 p9pdu_writef(pdu, proto_version,
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500422 "wwdQdddqssss?sddd",
423 stbuf->size, stbuf->type,
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500424 stbuf->dev, &stbuf->qid,
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500425 stbuf->mode, stbuf->atime,
426 stbuf->mtime, stbuf->length,
427 stbuf->name, stbuf->uid,
428 stbuf->gid, stbuf->muid,
429 stbuf->extension, stbuf->n_uid,
430 stbuf->n_gid, stbuf->n_muid);
431 } break;
432 case 'D':{
M. Mohan Kumar219fd582011-01-10 14:23:53 -0600433 uint32_t count = va_arg(ap, uint32_t);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500434 const void *data = va_arg(ap, const void *);
435
Sripathi Kodi342fee12010-03-05 18:50:14 +0000436 errcode = p9pdu_writef(pdu, proto_version, "d",
437 count);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500438 if (!errcode && pdu_write(pdu, data, count))
439 errcode = -EFAULT;
440 }
441 break;
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500442 case 'U':{
443 int32_t count = va_arg(ap, int32_t);
444 const char __user *udata =
Eric Van Hensbergene45c5402008-10-22 18:54:47 -0500445 va_arg(ap, const void __user *);
Sripathi Kodi342fee12010-03-05 18:50:14 +0000446 errcode = p9pdu_writef(pdu, proto_version, "d",
447 count);
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500448 if (!errcode && pdu_write_u(pdu, udata, count))
449 errcode = -EFAULT;
450 }
451 break;
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500452 case 'T':{
Harsh Prateek Borab76225e2011-03-31 15:49:39 +0530453 uint16_t nwname = va_arg(ap, int);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500454 const char **wnames = va_arg(ap, const char **);
455
Sripathi Kodi342fee12010-03-05 18:50:14 +0000456 errcode = p9pdu_writef(pdu, proto_version, "w",
457 nwname);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500458 if (!errcode) {
459 int i;
460
461 for (i = 0; i < nwname; i++) {
462 errcode =
Sripathi Kodi342fee12010-03-05 18:50:14 +0000463 p9pdu_writef(pdu,
464 proto_version,
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500465 "s",
466 wnames[i]);
467 if (errcode)
468 break;
469 }
470 }
471 }
472 break;
473 case 'R':{
474 int16_t nwqid = va_arg(ap, int);
475 struct p9_qid *wqids =
476 va_arg(ap, struct p9_qid *);
477
Sripathi Kodi342fee12010-03-05 18:50:14 +0000478 errcode = p9pdu_writef(pdu, proto_version, "w",
479 nwqid);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500480 if (!errcode) {
481 int i;
482
483 for (i = 0; i < nwqid; i++) {
484 errcode =
Sripathi Kodi342fee12010-03-05 18:50:14 +0000485 p9pdu_writef(pdu,
486 proto_version,
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500487 "Q",
488 &wqids[i]);
489 if (errcode)
490 break;
491 }
492 }
493 }
494 break;
Sripathi Kodi87d78452010-06-18 11:50:10 +0530495 case 'I':{
496 struct p9_iattr_dotl *p9attr = va_arg(ap,
497 struct p9_iattr_dotl *);
498
499 errcode = p9pdu_writef(pdu, proto_version,
500 "ddddqqqqq",
501 p9attr->valid,
502 p9attr->mode,
503 p9attr->uid,
504 p9attr->gid,
505 p9attr->size,
506 p9attr->atime_sec,
507 p9attr->atime_nsec,
508 p9attr->mtime_sec,
509 p9attr->mtime_nsec);
510 }
511 break;
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500512 case '?':
Sripathi Kodic56e4ac2010-03-25 12:40:35 +0000513 if ((proto_version != p9_proto_2000u) &&
514 (proto_version != p9_proto_2000L))
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500515 return 0;
516 break;
517 default:
518 BUG();
519 break;
520 }
521
522 if (errcode)
523 break;
524 }
525
526 return errcode;
527}
528
Sripathi Kodi342fee12010-03-05 18:50:14 +0000529int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500530{
531 va_list ap;
532 int ret;
533
534 va_start(ap, fmt);
Sripathi Kodi342fee12010-03-05 18:50:14 +0000535 ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500536 va_end(ap);
537
538 return ret;
539}
540
541static int
Sripathi Kodi342fee12010-03-05 18:50:14 +0000542p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500543{
544 va_list ap;
545 int ret;
546
547 va_start(ap, fmt);
Sripathi Kodi342fee12010-03-05 18:50:14 +0000548 ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
Eric Van Hensbergenace51c42008-10-13 20:40:27 -0500549 va_end(ap);
550
551 return ret;
552}
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500553
Sripathi Kodi342fee12010-03-05 18:50:14 +0000554int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
Eric Van Hensbergen02da3982008-10-16 08:29:30 -0500555{
556 struct p9_fcall fake_pdu;
Eric Van Hensbergene7f4b8f2008-10-17 16:20:07 -0500557 int ret;
Eric Van Hensbergen02da3982008-10-16 08:29:30 -0500558
559 fake_pdu.size = len;
560 fake_pdu.capacity = len;
561 fake_pdu.sdata = buf;
562 fake_pdu.offset = 0;
563
Sripathi Kodi342fee12010-03-05 18:50:14 +0000564 ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
Eric Van Hensbergene7f4b8f2008-10-17 16:20:07 -0500565 if (ret) {
566 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
Eric Van Hensbergene660a822011-06-19 16:38:21 -0500567 P9_DUMP_PKT(0, &fake_pdu);
Eric Van Hensbergene7f4b8f2008-10-17 16:20:07 -0500568 }
569
570 return ret;
Eric Van Hensbergen02da3982008-10-16 08:29:30 -0500571}
572EXPORT_SYMBOL(p9stat_read);
573
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500574int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
575{
Venkateswararao Jujjuri (JV)9bb6c102011-02-02 17:52:46 -0800576 pdu->id = type;
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500577 return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
578}
579
580int p9pdu_finalize(struct p9_fcall *pdu)
581{
582 int size = pdu->size;
583 int err;
584
585 pdu->size = 0;
586 err = p9pdu_writef(pdu, 0, "d", size);
587 pdu->size = size;
588
Eric Van Hensbergene660a822011-06-19 16:38:21 -0500589 P9_DUMP_PKT(0, pdu);
Eric Van Hensbergene7f4b8f2008-10-17 16:20:07 -0500590 P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
591 pdu->id, pdu->tag);
592
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500593 return err;
594}
595
596void p9pdu_reset(struct p9_fcall *pdu)
597{
598 pdu->offset = 0;
599 pdu->size = 0;
600}
Sripathi Kodi7751bdb2010-06-04 13:41:26 +0000601
602int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
603 int proto_version)
604{
605 struct p9_fcall fake_pdu;
606 int ret;
607 char *nameptr;
608
609 fake_pdu.size = len;
610 fake_pdu.capacity = len;
611 fake_pdu.sdata = buf;
612 fake_pdu.offset = 0;
613
614 ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
615 &dirent->d_off, &dirent->d_type, &nameptr);
616 if (ret) {
617 P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
Eric Van Hensbergene660a822011-06-19 16:38:21 -0500618 P9_DUMP_PKT(1, &fake_pdu);
Sripathi Kodi7751bdb2010-06-04 13:41:26 +0000619 goto out;
620 }
621
622 strcpy(dirent->d_name, nameptr);
Pedro Scarapicchia Junior1b0bcbcf62011-05-09 14:10:49 +0000623 kfree(nameptr);
Sripathi Kodi7751bdb2010-06-04 13:41:26 +0000624
625out:
626 return fake_pdu.offset;
627}
628EXPORT_SYMBOL(p9dirent_read);