blob: 56d88c1a09c566baa5a0733f728cc7a8819b97b7 [file] [log] [blame]
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -07001/*
2 * linux/fs/9p/conv.c
3 *
4 * 9P protocol conversion functions
5 *
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -07006 * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -07007 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9 *
10 * This program is free software; you can redistribute it and/or modify
Eric Van Hensbergen42e8c502006-03-25 03:07:28 -080011 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070013 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070027#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/fs.h>
30#include <linux/idr.h>
Latchesar Ionkov531b1092006-01-08 01:05:00 -080031#include <asm/uaccess.h>
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070032#include "debug.h"
33#include "v9fs.h"
34#include "9p.h"
35#include "conv.h"
36
37/*
38 * Buffer to help with string parsing
39 */
40struct cbuf {
41 unsigned char *sp;
42 unsigned char *p;
43 unsigned char *ep;
44};
45
46static inline void buf_init(struct cbuf *buf, void *data, int datalen)
47{
48 buf->sp = buf->p = data;
49 buf->ep = data + datalen;
50}
51
52static inline int buf_check_overflow(struct cbuf *buf)
53{
54 return buf->p > buf->ep;
55}
56
Arjan van de Ven858119e2006-01-14 13:20:43 -080057static int buf_check_size(struct cbuf *buf, int len)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070058{
Latchesar Ionkov1dac06b2006-01-08 01:05:02 -080059 if (buf->p + len > buf->ep) {
60 if (buf->p < buf->ep) {
61 eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
62 len, (int)(buf->ep - buf->p));
63 dump_stack();
64 buf->p = buf->ep + 1;
65 }
66
Latchesar Ionkov531b1092006-01-08 01:05:00 -080067 return 0;
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070068 }
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -070069
70 return 1;
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070071}
72
Arjan van de Ven858119e2006-01-14 13:20:43 -080073static void *buf_alloc(struct cbuf *buf, int len)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070074{
75 void *ret = NULL;
76
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -070077 if (buf_check_size(buf, len)) {
78 ret = buf->p;
79 buf->p += len;
80 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070081
82 return ret;
83}
84
Arjan van de Ven858119e2006-01-14 13:20:43 -080085static void buf_put_int8(struct cbuf *buf, u8 val)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070086{
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -070087 if (buf_check_size(buf, 1)) {
88 buf->p[0] = val;
89 buf->p++;
90 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070091}
92
Arjan van de Ven858119e2006-01-14 13:20:43 -080093static void buf_put_int16(struct cbuf *buf, u16 val)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070094{
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -070095 if (buf_check_size(buf, 2)) {
96 *(__le16 *) buf->p = cpu_to_le16(val);
97 buf->p += 2;
98 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -070099}
100
Arjan van de Ven858119e2006-01-14 13:20:43 -0800101static void buf_put_int32(struct cbuf *buf, u32 val)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700102{
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -0700103 if (buf_check_size(buf, 4)) {
104 *(__le32 *)buf->p = cpu_to_le32(val);
105 buf->p += 4;
106 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700107}
108
Arjan van de Ven858119e2006-01-14 13:20:43 -0800109static void buf_put_int64(struct cbuf *buf, u64 val)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700110{
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -0700111 if (buf_check_size(buf, 8)) {
112 *(__le64 *)buf->p = cpu_to_le64(val);
113 buf->p += 8;
114 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700115}
116
Latchesar Ionkov05818a02006-02-03 03:04:18 -0800117static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700118{
Latchesar Ionkov05818a02006-02-03 03:04:18 -0800119 char *ret;
120
121 ret = NULL;
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -0700122 if (buf_check_size(buf, slen + 2)) {
123 buf_put_int16(buf, slen);
Latchesar Ionkov05818a02006-02-03 03:04:18 -0800124 ret = buf->p;
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -0700125 memcpy(buf->p, s, slen);
126 buf->p += slen;
127 }
Latchesar Ionkov05818a02006-02-03 03:04:18 -0800128
129 return ret;
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700130}
131
132static inline void buf_put_string(struct cbuf *buf, const char *s)
133{
134 buf_put_stringn(buf, s, strlen(s));
135}
136
Arjan van de Ven858119e2006-01-14 13:20:43 -0800137static u8 buf_get_int8(struct cbuf *buf)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700138{
139 u8 ret = 0;
140
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -0700141 if (buf_check_size(buf, 1)) {
142 ret = buf->p[0];
143 buf->p++;
144 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700145
146 return ret;
147}
148
Arjan van de Ven858119e2006-01-14 13:20:43 -0800149static u16 buf_get_int16(struct cbuf *buf)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700150{
151 u16 ret = 0;
152
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -0700153 if (buf_check_size(buf, 2)) {
154 ret = le16_to_cpu(*(__le16 *)buf->p);
155 buf->p += 2;
156 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700157
158 return ret;
159}
160
Arjan van de Ven858119e2006-01-14 13:20:43 -0800161static u32 buf_get_int32(struct cbuf *buf)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700162{
163 u32 ret = 0;
164
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -0700165 if (buf_check_size(buf, 4)) {
166 ret = le32_to_cpu(*(__le32 *)buf->p);
167 buf->p += 4;
168 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700169
170 return ret;
171}
172
Arjan van de Ven858119e2006-01-14 13:20:43 -0800173static u64 buf_get_int64(struct cbuf *buf)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700174{
175 u64 ret = 0;
176
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -0700177 if (buf_check_size(buf, 8)) {
178 ret = le64_to_cpu(*(__le64 *)buf->p);
179 buf->p += 8;
180 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700181
182 return ret;
183}
184
Arjan van de Ven858119e2006-01-14 13:20:43 -0800185static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700186{
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800187 vstr->len = buf_get_int16(buf);
188 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
189 vstr->str = buf->p;
190 buf->p += vstr->len;
191 } else {
192 vstr->len = 0;
193 vstr->str = NULL;
Latchesar Ionkovd06a8fb2005-09-22 21:43:48 -0700194 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700195}
196
Arjan van de Ven858119e2006-01-14 13:20:43 -0800197static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700198{
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800199 qid->type = buf_get_int8(bufp);
200 qid->version = buf_get_int32(bufp);
201 qid->path = buf_get_int64(bufp);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700202}
203
204/**
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800205 * v9fs_size_wstat - calculate the size of a variable length stat struct
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700206 * @stat: metadata (stat) structure
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800207 * @extended: non-zero if 9P2000.u
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700208 *
209 */
210
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800211static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700212{
213 int size = 0;
214
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800215 if (wstat == NULL) {
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700216 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
217 return 0;
218 }
219
220 size = /* 2 + *//* size[2] */
221 2 + /* type[2] */
222 4 + /* dev[4] */
223 1 + /* qid.type[1] */
224 4 + /* qid.vers[4] */
225 8 + /* qid.path[8] */
226 4 + /* mode[4] */
227 4 + /* atime[4] */
228 4 + /* mtime[4] */
229 8 + /* length[8] */
230 8; /* minimum sum of string lengths */
231
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800232 if (wstat->name)
233 size += strlen(wstat->name);
234 if (wstat->uid)
235 size += strlen(wstat->uid);
236 if (wstat->gid)
237 size += strlen(wstat->gid);
238 if (wstat->muid)
239 size += strlen(wstat->muid);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700240
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800241 if (extended) {
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700242 size += 4 + /* n_uid[4] */
243 4 + /* n_gid[4] */
244 4 + /* n_muid[4] */
245 2; /* string length of extension[4] */
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800246 if (wstat->extension)
247 size += strlen(wstat->extension);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700248 }
249
250 return size;
251}
252
253/**
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800254 * buf_get_stat - safely decode a recieved metadata (stat) structure
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700255 * @bufp: buffer to deserialize
256 * @stat: metadata (stat) structure
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800257 * @extended: non-zero if 9P2000.u
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700258 *
259 */
260
Arjan van de Ven858119e2006-01-14 13:20:43 -0800261static void
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800262buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700263{
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700264 stat->size = buf_get_int16(bufp);
265 stat->type = buf_get_int16(bufp);
266 stat->dev = buf_get_int32(bufp);
267 stat->qid.type = buf_get_int8(bufp);
268 stat->qid.version = buf_get_int32(bufp);
269 stat->qid.path = buf_get_int64(bufp);
270 stat->mode = buf_get_int32(bufp);
271 stat->atime = buf_get_int32(bufp);
272 stat->mtime = buf_get_int32(bufp);
273 stat->length = buf_get_int64(bufp);
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800274 buf_get_str(bufp, &stat->name);
275 buf_get_str(bufp, &stat->uid);
276 buf_get_str(bufp, &stat->gid);
277 buf_get_str(bufp, &stat->muid);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700278
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800279 if (extended) {
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800280 buf_get_str(bufp, &stat->extension);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700281 stat->n_uid = buf_get_int32(bufp);
282 stat->n_gid = buf_get_int32(bufp);
283 stat->n_muid = buf_get_int32(bufp);
284 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700285}
286
287/**
288 * v9fs_deserialize_stat - decode a received metadata structure
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700289 * @buf: buffer to deserialize
290 * @buflen: length of received buffer
291 * @stat: metadata structure to decode into
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800292 * @extended: non-zero if 9P2000.u
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700293 *
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800294 * Note: stat will point to the buf region.
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700295 */
296
297int
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800298v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
299 int extended)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700300{
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700301 struct cbuf buffer;
302 struct cbuf *bufp = &buffer;
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800303 unsigned char *p;
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700304
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800305 buf_init(bufp, buf, buflen);
306 p = bufp->p;
307 buf_get_stat(bufp, stat, extended);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700308
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800309 if (buf_check_overflow(bufp))
310 return 0;
311 else
312 return bufp->p - p;
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700313}
314
315/**
316 * deserialize_fcall - unmarshal a response
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700317 * @buf: recieved buffer
318 * @buflen: length of received buffer
319 * @rcall: fcall structure to populate
320 * @rcalllen: length of fcall structure to populate
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800321 * @extended: non-zero if 9P2000.u
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700322 *
323 */
324
325int
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800326v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800327 int extended)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700328{
329
330 struct cbuf buffer;
331 struct cbuf *bufp = &buffer;
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700332 int i = 0;
333
334 buf_init(bufp, buf, buflen);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700335
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800336 rcall->size = buf_get_int32(bufp);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700337 rcall->id = buf_get_int8(bufp);
338 rcall->tag = buf_get_int16(bufp);
339
340 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
341 rcall->tag);
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800342
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700343 switch (rcall->id) {
344 default:
345 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
346 return -EPROTO;
347 case RVERSION:
348 rcall->params.rversion.msize = buf_get_int32(bufp);
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800349 buf_get_str(bufp, &rcall->params.rversion.version);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700350 break;
351 case RFLUSH:
352 break;
353 case RATTACH:
354 rcall->params.rattach.qid.type = buf_get_int8(bufp);
355 rcall->params.rattach.qid.version = buf_get_int32(bufp);
356 rcall->params.rattach.qid.path = buf_get_int64(bufp);
357 break;
358 case RWALK:
359 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800360 if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
361 eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
362 V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800363 return -EPROTO;
364 }
365
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800366 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
367 buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700368 break;
369 case ROPEN:
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800370 buf_get_qid(bufp, &rcall->params.ropen.qid);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700371 rcall->params.ropen.iounit = buf_get_int32(bufp);
372 break;
373 case RCREATE:
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800374 buf_get_qid(bufp, &rcall->params.rcreate.qid);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700375 rcall->params.rcreate.iounit = buf_get_int32(bufp);
376 break;
377 case RREAD:
378 rcall->params.rread.count = buf_get_int32(bufp);
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800379 rcall->params.rread.data = bufp->p;
380 buf_check_size(bufp, rcall->params.rread.count);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700381 break;
382 case RWRITE:
383 rcall->params.rwrite.count = buf_get_int32(bufp);
384 break;
385 case RCLUNK:
386 break;
387 case RREMOVE:
388 break;
389 case RSTAT:
390 buf_get_int16(bufp);
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800391 buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700392 break;
393 case RWSTAT:
394 break;
395 case RERROR:
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800396 buf_get_str(bufp, &rcall->params.rerror.error);
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800397 if (extended)
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700398 rcall->params.rerror.errno = buf_get_int16(bufp);
399 break;
400 }
401
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800402 if (buf_check_overflow(bufp)) {
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800403 dprintk(DEBUG_ERROR, "buffer overflow\n");
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700404 return -EIO;
Latchesar Ionkov3cf64292006-01-08 01:04:58 -0800405 }
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700406
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800407 return bufp->p - bufp->sp;
408}
409
410static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
411{
412 *p = val;
413 buf_put_int8(bufp, val);
414}
415
416static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
417{
418 *p = val;
419 buf_put_int16(bufp, val);
420}
421
422static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
423{
424 *p = val;
425 buf_put_int32(bufp, val);
426}
427
428static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
429{
430 *p = val;
431 buf_put_int64(bufp, val);
432}
433
Arjan van de Ven858119e2006-01-14 13:20:43 -0800434static void
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800435v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
436{
Latchesar Ionkov05818a02006-02-03 03:04:18 -0800437 int len;
438 char *s;
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800439
Latchesar Ionkov05818a02006-02-03 03:04:18 -0800440 if (data)
441 len = strlen(data);
442 else
443 len = 0;
444
445 s = buf_put_stringn(bufp, data, len);
446 if (str) {
447 str->len = len;
448 str->str = s;
449 }
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800450}
451
Arjan van de Ven858119e2006-01-14 13:20:43 -0800452static int
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800453v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
454 unsigned char **pdata)
455{
456 *pdata = buf_alloc(bufp, count);
457 return copy_from_user(*pdata, data, count);
458}
459
460static void
461v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
462 struct v9fs_stat *stat, int statsz, int extended)
463{
464 v9fs_put_int16(bufp, statsz, &stat->size);
465 v9fs_put_int16(bufp, wstat->type, &stat->type);
466 v9fs_put_int32(bufp, wstat->dev, &stat->dev);
467 v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
468 v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
469 v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
470 v9fs_put_int32(bufp, wstat->mode, &stat->mode);
471 v9fs_put_int32(bufp, wstat->atime, &stat->atime);
472 v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
473 v9fs_put_int64(bufp, wstat->length, &stat->length);
474
475 v9fs_put_str(bufp, wstat->name, &stat->name);
476 v9fs_put_str(bufp, wstat->uid, &stat->uid);
477 v9fs_put_str(bufp, wstat->gid, &stat->gid);
478 v9fs_put_str(bufp, wstat->muid, &stat->muid);
479
480 if (extended) {
481 v9fs_put_str(bufp, wstat->extension, &stat->extension);
482 v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
483 v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
484 v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
485 }
486}
487
488static struct v9fs_fcall *
489v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
490{
491 struct v9fs_fcall *fc;
492
493 size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
494 fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
495 if (!fc)
496 return ERR_PTR(-ENOMEM);
497
498 fc->sdata = (char *)fc + sizeof(*fc);
499
500 buf_init(bufp, (char *)fc->sdata, size);
501 v9fs_put_int32(bufp, size, &fc->size);
502 v9fs_put_int8(bufp, id, &fc->id);
503 v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
504
505 return fc;
506}
507
508void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
509{
Latchesar Ionkov1dac06b2006-01-08 01:05:02 -0800510 fc->tag = tag;
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800511 *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
512}
513
514struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
515{
516 int size;
517 struct v9fs_fcall *fc;
518 struct cbuf buffer;
519 struct cbuf *bufp = &buffer;
520
521 size = 4 + 2 + strlen(version); /* msize[4] version[s] */
522 fc = v9fs_create_common(bufp, size, TVERSION);
523 if (IS_ERR(fc))
524 goto error;
525
526 v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
527 v9fs_put_str(bufp, version, &fc->params.tversion.version);
528
529 if (buf_check_overflow(bufp)) {
530 kfree(fc);
531 fc = ERR_PTR(-ENOMEM);
532 }
533 error:
534 return fc;
535}
536
Adrian Bunk29c6e482006-03-24 03:15:52 -0800537#if 0
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800538struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
539{
540 int size;
541 struct v9fs_fcall *fc;
542 struct cbuf buffer;
543 struct cbuf *bufp = &buffer;
544
545 size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */
546 fc = v9fs_create_common(bufp, size, TAUTH);
547 if (IS_ERR(fc))
548 goto error;
549
550 v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
551 v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
552 v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
553
554 if (buf_check_overflow(bufp)) {
555 kfree(fc);
556 fc = ERR_PTR(-ENOMEM);
557 }
558 error:
559 return fc;
560}
Adrian Bunk29c6e482006-03-24 03:15:52 -0800561#endif /* 0 */
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800562
563struct v9fs_fcall *
564v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
565{
566 int size;
567 struct v9fs_fcall *fc;
568 struct cbuf buffer;
569 struct cbuf *bufp = &buffer;
570
571 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */
572 fc = v9fs_create_common(bufp, size, TATTACH);
573 if (IS_ERR(fc))
574 goto error;
575
576 v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
577 v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
578 v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
579 v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
580
581 error:
582 return fc;
583}
584
585struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
586{
587 int size;
588 struct v9fs_fcall *fc;
589 struct cbuf buffer;
590 struct cbuf *bufp = &buffer;
591
592 size = 2; /* oldtag[2] */
593 fc = v9fs_create_common(bufp, size, TFLUSH);
594 if (IS_ERR(fc))
595 goto error;
596
597 v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
598
599 if (buf_check_overflow(bufp)) {
600 kfree(fc);
601 fc = ERR_PTR(-ENOMEM);
602 }
603 error:
604 return fc;
605}
606
607struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
608 char **wnames)
609{
610 int i, size;
611 struct v9fs_fcall *fc;
612 struct cbuf buffer;
613 struct cbuf *bufp = &buffer;
614
615 if (nwname > V9FS_MAXWELEM) {
616 dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
617 return NULL;
618 }
619
620 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
621 for (i = 0; i < nwname; i++) {
622 size += 2 + strlen(wnames[i]); /* wname[s] */
623 }
624
625 fc = v9fs_create_common(bufp, size, TWALK);
626 if (IS_ERR(fc))
627 goto error;
628
629 v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
630 v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
631 v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
632 for (i = 0; i < nwname; i++) {
633 v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
634 }
635
636 if (buf_check_overflow(bufp)) {
637 kfree(fc);
638 fc = ERR_PTR(-ENOMEM);
639 }
640 error:
641 return fc;
642}
643
644struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
645{
646 int size;
647 struct v9fs_fcall *fc;
648 struct cbuf buffer;
649 struct cbuf *bufp = &buffer;
650
651 size = 4 + 1; /* fid[4] mode[1] */
652 fc = v9fs_create_common(bufp, size, TOPEN);
653 if (IS_ERR(fc))
654 goto error;
655
656 v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
657 v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
658
659 if (buf_check_overflow(bufp)) {
660 kfree(fc);
661 fc = ERR_PTR(-ENOMEM);
662 }
663 error:
664 return fc;
665}
666
Latchesar Ionkov16cce6d2006-03-25 03:07:26 -0800667struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
668 char *extension, int extended)
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800669{
670 int size;
671 struct v9fs_fcall *fc;
672 struct cbuf buffer;
673 struct cbuf *bufp = &buffer;
674
675 size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */
Russ Ross4c90c682006-07-30 03:04:15 -0700676 if (extended) {
677 size += 2 + /* extension[s] */
678 (extension == NULL ? 0 : strlen(extension));
679 }
Latchesar Ionkov16cce6d2006-03-25 03:07:26 -0800680
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800681 fc = v9fs_create_common(bufp, size, TCREATE);
682 if (IS_ERR(fc))
683 goto error;
684
685 v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
686 v9fs_put_str(bufp, name, &fc->params.tcreate.name);
687 v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
688 v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
Latchesar Ionkov16cce6d2006-03-25 03:07:26 -0800689 if (extended)
690 v9fs_put_str(bufp, extension, &fc->params.tcreate.extension);
Latchesar Ionkov531b1092006-01-08 01:05:00 -0800691
692 if (buf_check_overflow(bufp)) {
693 kfree(fc);
694 fc = ERR_PTR(-ENOMEM);
695 }
696 error:
697 return fc;
698}
699
700struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
701{
702 int size;
703 struct v9fs_fcall *fc;
704 struct cbuf buffer;
705 struct cbuf *bufp = &buffer;
706
707 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
708 fc = v9fs_create_common(bufp, size, TREAD);
709 if (IS_ERR(fc))
710 goto error;
711
712 v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
713 v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
714 v9fs_put_int32(bufp, count, &fc->params.tread.count);
715
716 if (buf_check_overflow(bufp)) {
717 kfree(fc);
718 fc = ERR_PTR(-ENOMEM);
719 }
720 error:
721 return fc;
722}
723
724struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
725 const char __user * data)
726{
727 int size, err;
728 struct v9fs_fcall *fc;
729 struct cbuf buffer;
730 struct cbuf *bufp = &buffer;
731
732 size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */
733 fc = v9fs_create_common(bufp, size, TWRITE);
734 if (IS_ERR(fc))
735 goto error;
736
737 v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
738 v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
739 v9fs_put_int32(bufp, count, &fc->params.twrite.count);
740 err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
741 if (err) {
742 kfree(fc);
743 fc = ERR_PTR(err);
744 }
745
746 if (buf_check_overflow(bufp)) {
747 kfree(fc);
748 fc = ERR_PTR(-ENOMEM);
749 }
750 error:
751 return fc;
752}
753
754struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
755{
756 int size;
757 struct v9fs_fcall *fc;
758 struct cbuf buffer;
759 struct cbuf *bufp = &buffer;
760
761 size = 4; /* fid[4] */
762 fc = v9fs_create_common(bufp, size, TCLUNK);
763 if (IS_ERR(fc))
764 goto error;
765
766 v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
767
768 if (buf_check_overflow(bufp)) {
769 kfree(fc);
770 fc = ERR_PTR(-ENOMEM);
771 }
772 error:
773 return fc;
774}
775
776struct v9fs_fcall *v9fs_create_tremove(u32 fid)
777{
778 int size;
779 struct v9fs_fcall *fc;
780 struct cbuf buffer;
781 struct cbuf *bufp = &buffer;
782
783 size = 4; /* fid[4] */
784 fc = v9fs_create_common(bufp, size, TREMOVE);
785 if (IS_ERR(fc))
786 goto error;
787
788 v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
789
790 if (buf_check_overflow(bufp)) {
791 kfree(fc);
792 fc = ERR_PTR(-ENOMEM);
793 }
794 error:
795 return fc;
796}
797
798struct v9fs_fcall *v9fs_create_tstat(u32 fid)
799{
800 int size;
801 struct v9fs_fcall *fc;
802 struct cbuf buffer;
803 struct cbuf *bufp = &buffer;
804
805 size = 4; /* fid[4] */
806 fc = v9fs_create_common(bufp, size, TSTAT);
807 if (IS_ERR(fc))
808 goto error;
809
810 v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
811
812 if (buf_check_overflow(bufp)) {
813 kfree(fc);
814 fc = ERR_PTR(-ENOMEM);
815 }
816 error:
817 return fc;
818}
819
820struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
821 int extended)
822{
823 int size, statsz;
824 struct v9fs_fcall *fc;
825 struct cbuf buffer;
826 struct cbuf *bufp = &buffer;
827
828 statsz = v9fs_size_wstat(wstat, extended);
829 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
830 fc = v9fs_create_common(bufp, size, TWSTAT);
831 if (IS_ERR(fc))
832 goto error;
833
834 v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
835 buf_put_int16(bufp, statsz + 2);
836 v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
837
838 if (buf_check_overflow(bufp)) {
839 kfree(fc);
840 fc = ERR_PTR(-ENOMEM);
841 }
842 error:
843 return fc;
Eric Van Hensbergenb8cf9452005-09-09 13:04:21 -0700844}