diff options
author | Latchesar Ionkov <lucho@ionkov.net> | 2006-01-08 04:05:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 23:14:06 -0500 |
commit | 531b1094b74365dcc55fa464d28a9a2497ae825d (patch) | |
tree | a0384dabe3be1c844166d028b3ef7c21c3dfe5fc /fs/9p/conv.c | |
parent | d8da097afb765654c866062148fd98b11db9003e (diff) |
[PATCH] v9fs: zero copy implementation
Performance enhancement reducing the number of copies in the data and
stat paths.
Signed-off-by: Latchesar Ionkov <lucho@ionkov.net>
Cc: Eric Van Hensbergen <ericvh@ericvh.myip.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/9p/conv.c')
-rw-r--r-- | fs/9p/conv.c | 895 |
1 files changed, 518 insertions, 377 deletions
diff --git a/fs/9p/conv.c b/fs/9p/conv.c index 1b9b15dfeaf0..f62434d435b3 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
32 | #include <linux/idr.h> | 32 | #include <linux/idr.h> |
33 | 33 | #include <asm/uaccess.h> | |
34 | #include "debug.h" | 34 | #include "debug.h" |
35 | #include "v9fs.h" | 35 | #include "v9fs.h" |
36 | #include "9p.h" | 36 | #include "9p.h" |
@@ -45,6 +45,37 @@ struct cbuf { | |||
45 | unsigned char *ep; | 45 | unsigned char *ep; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str) | ||
49 | { | ||
50 | int n; | ||
51 | |||
52 | if (buflen < str->len) | ||
53 | n = buflen; | ||
54 | else | ||
55 | n = str->len; | ||
56 | |||
57 | memmove(buf, str->str, n - 1); | ||
58 | |||
59 | return buf; | ||
60 | } | ||
61 | |||
62 | int v9fs_str_compare(char *buf, struct v9fs_str *str) | ||
63 | { | ||
64 | int n, ret; | ||
65 | |||
66 | ret = strncmp(buf, str->str, str->len); | ||
67 | |||
68 | if (!ret) { | ||
69 | n = strlen(buf); | ||
70 | if (n < str->len) | ||
71 | ret = -1; | ||
72 | else if (n > str->len) | ||
73 | ret = 1; | ||
74 | } | ||
75 | |||
76 | return ret; | ||
77 | } | ||
78 | |||
48 | static inline void buf_init(struct cbuf *buf, void *data, int datalen) | 79 | static inline void buf_init(struct cbuf *buf, void *data, int datalen) |
49 | { | 80 | { |
50 | buf->sp = buf->p = data; | 81 | buf->sp = buf->p = data; |
@@ -58,12 +89,12 @@ static inline int buf_check_overflow(struct cbuf *buf) | |||
58 | 89 | ||
59 | static inline int buf_check_size(struct cbuf *buf, int len) | 90 | static inline int buf_check_size(struct cbuf *buf, int len) |
60 | { | 91 | { |
61 | if (buf->p+len > buf->ep) { | 92 | if (buf->p + len > buf->ep && buf->p < buf->ep) { |
62 | if (buf->p < buf->ep) { | 93 | eprintk(KERN_ERR, "buffer overflow: want %d has %d\n", |
63 | eprintk(KERN_ERR, "buffer overflow\n"); | 94 | len, (int)(buf->ep - buf->p)); |
64 | buf->p = buf->ep + 1; | 95 | dump_stack(); |
65 | return 0; | 96 | buf->p = buf->ep + 1; |
66 | } | 97 | return 0; |
67 | } | 98 | } |
68 | 99 | ||
69 | return 1; | 100 | return 1; |
@@ -127,14 +158,6 @@ static inline void buf_put_string(struct cbuf *buf, const char *s) | |||
127 | buf_put_stringn(buf, s, strlen(s)); | 158 | buf_put_stringn(buf, s, strlen(s)); |
128 | } | 159 | } |
129 | 160 | ||
130 | static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen) | ||
131 | { | ||
132 | if (buf_check_size(buf, datalen)) { | ||
133 | memcpy(buf->p, data, datalen); | ||
134 | buf->p += datalen; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | static inline u8 buf_get_int8(struct cbuf *buf) | 161 | static inline u8 buf_get_int8(struct cbuf *buf) |
139 | { | 162 | { |
140 | u8 ret = 0; | 163 | u8 ret = 0; |
@@ -183,85 +206,37 @@ static inline u64 buf_get_int64(struct cbuf *buf) | |||
183 | return ret; | 206 | return ret; |
184 | } | 207 | } |
185 | 208 | ||
186 | static inline int | 209 | static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr) |
187 | buf_get_string(struct cbuf *buf, char *data, unsigned int datalen) | ||
188 | { | ||
189 | u16 len = 0; | ||
190 | |||
191 | len = buf_get_int16(buf); | ||
192 | if (!buf_check_overflow(buf) && buf_check_size(buf, len) && len+1>datalen) { | ||
193 | memcpy(data, buf->p, len); | ||
194 | data[len] = 0; | ||
195 | buf->p += len; | ||
196 | len++; | ||
197 | } | ||
198 | |||
199 | return len; | ||
200 | } | ||
201 | |||
202 | static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) | ||
203 | { | ||
204 | char *ret; | ||
205 | u16 len; | ||
206 | |||
207 | ret = NULL; | ||
208 | len = buf_get_int16(buf); | ||
209 | |||
210 | if (!buf_check_overflow(buf) && buf_check_size(buf, len) && | ||
211 | buf_check_size(sbuf, len + 1)) { | ||
212 | |||
213 | memcpy(sbuf->p, buf->p, len); | ||
214 | sbuf->p[len] = 0; | ||
215 | ret = sbuf->p; | ||
216 | buf->p += len; | ||
217 | sbuf->p += len + 1; | ||
218 | } | ||
219 | |||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | static inline int buf_get_data(struct cbuf *buf, void *data, int datalen) | ||
224 | { | 210 | { |
225 | int ret = 0; | 211 | vstr->len = buf_get_int16(buf); |
226 | 212 | if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { | |
227 | if (buf_check_size(buf, datalen)) { | 213 | vstr->str = buf->p; |
228 | memcpy(data, buf->p, datalen); | 214 | buf->p += vstr->len; |
229 | buf->p += datalen; | 215 | } else { |
230 | ret = datalen; | 216 | vstr->len = 0; |
217 | vstr->str = NULL; | ||
231 | } | 218 | } |
232 | |||
233 | return ret; | ||
234 | } | 219 | } |
235 | 220 | ||
236 | static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, | 221 | static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid) |
237 | int datalen) | ||
238 | { | 222 | { |
239 | char *ret = NULL; | 223 | qid->type = buf_get_int8(bufp); |
240 | int n = 0; | 224 | qid->version = buf_get_int32(bufp); |
241 | 225 | qid->path = buf_get_int64(bufp); | |
242 | if (buf_check_size(dbuf, datalen)) { | ||
243 | n = buf_get_data(buf, dbuf->p, datalen); | ||
244 | if (n > 0) { | ||
245 | ret = dbuf->p; | ||
246 | dbuf->p += n; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | return ret; | ||
251 | } | 226 | } |
252 | 227 | ||
253 | /** | 228 | /** |
254 | * v9fs_size_stat - calculate the size of a variable length stat struct | 229 | * v9fs_size_wstat - calculate the size of a variable length stat struct |
255 | * @stat: metadata (stat) structure | 230 | * @stat: metadata (stat) structure |
256 | * @extended: non-zero if 9P2000.u | 231 | * @extended: non-zero if 9P2000.u |
257 | * | 232 | * |
258 | */ | 233 | */ |
259 | 234 | ||
260 | static int v9fs_size_stat(struct v9fs_stat *stat, int extended) | 235 | static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended) |
261 | { | 236 | { |
262 | int size = 0; | 237 | int size = 0; |
263 | 238 | ||
264 | if (stat == NULL) { | 239 | if (wstat == NULL) { |
265 | eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); | 240 | eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); |
266 | return 0; | 241 | return 0; |
267 | } | 242 | } |
@@ -278,81 +253,38 @@ static int v9fs_size_stat(struct v9fs_stat *stat, int extended) | |||
278 | 8 + /* length[8] */ | 253 | 8 + /* length[8] */ |
279 | 8; /* minimum sum of string lengths */ | 254 | 8; /* minimum sum of string lengths */ |
280 | 255 | ||
281 | if (stat->name) | 256 | if (wstat->name) |
282 | size += strlen(stat->name); | 257 | size += strlen(wstat->name); |
283 | if (stat->uid) | 258 | if (wstat->uid) |
284 | size += strlen(stat->uid); | 259 | size += strlen(wstat->uid); |
285 | if (stat->gid) | 260 | if (wstat->gid) |
286 | size += strlen(stat->gid); | 261 | size += strlen(wstat->gid); |
287 | if (stat->muid) | 262 | if (wstat->muid) |
288 | size += strlen(stat->muid); | 263 | size += strlen(wstat->muid); |
289 | 264 | ||
290 | if (extended) { | 265 | if (extended) { |
291 | size += 4 + /* n_uid[4] */ | 266 | size += 4 + /* n_uid[4] */ |
292 | 4 + /* n_gid[4] */ | 267 | 4 + /* n_gid[4] */ |
293 | 4 + /* n_muid[4] */ | 268 | 4 + /* n_muid[4] */ |
294 | 2; /* string length of extension[4] */ | 269 | 2; /* string length of extension[4] */ |
295 | if (stat->extension) | 270 | if (wstat->extension) |
296 | size += strlen(stat->extension); | 271 | size += strlen(wstat->extension); |
297 | } | 272 | } |
298 | 273 | ||
299 | return size; | 274 | return size; |
300 | } | 275 | } |
301 | 276 | ||
302 | /** | 277 | /** |
303 | * serialize_stat - safely format a stat structure for transmission | 278 | * buf_get_stat - safely decode a recieved metadata (stat) structure |
304 | * @stat: metadata (stat) structure | ||
305 | * @bufp: buffer to serialize structure into | ||
306 | * @extended: non-zero if 9P2000.u | ||
307 | * | ||
308 | */ | ||
309 | |||
310 | static int | ||
311 | serialize_stat(struct v9fs_stat *stat, struct cbuf *bufp, int extended) | ||
312 | { | ||
313 | buf_put_int16(bufp, stat->size); | ||
314 | buf_put_int16(bufp, stat->type); | ||
315 | buf_put_int32(bufp, stat->dev); | ||
316 | buf_put_int8(bufp, stat->qid.type); | ||
317 | buf_put_int32(bufp, stat->qid.version); | ||
318 | buf_put_int64(bufp, stat->qid.path); | ||
319 | buf_put_int32(bufp, stat->mode); | ||
320 | buf_put_int32(bufp, stat->atime); | ||
321 | buf_put_int32(bufp, stat->mtime); | ||
322 | buf_put_int64(bufp, stat->length); | ||
323 | |||
324 | buf_put_string(bufp, stat->name); | ||
325 | buf_put_string(bufp, stat->uid); | ||
326 | buf_put_string(bufp, stat->gid); | ||
327 | buf_put_string(bufp, stat->muid); | ||
328 | |||
329 | if (extended) { | ||
330 | buf_put_string(bufp, stat->extension); | ||
331 | buf_put_int32(bufp, stat->n_uid); | ||
332 | buf_put_int32(bufp, stat->n_gid); | ||
333 | buf_put_int32(bufp, stat->n_muid); | ||
334 | } | ||
335 | |||
336 | if (buf_check_overflow(bufp)) | ||
337 | return 0; | ||
338 | |||
339 | return stat->size; | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * deserialize_stat - safely decode a recieved metadata (stat) structure | ||
344 | * @bufp: buffer to deserialize | 279 | * @bufp: buffer to deserialize |
345 | * @stat: metadata (stat) structure | 280 | * @stat: metadata (stat) structure |
346 | * @dbufp: buffer to deserialize variable strings into | ||
347 | * @extended: non-zero if 9P2000.u | 281 | * @extended: non-zero if 9P2000.u |
348 | * | 282 | * |
349 | */ | 283 | */ |
350 | 284 | ||
351 | static inline int | 285 | static inline void |
352 | deserialize_stat(struct cbuf *bufp, struct v9fs_stat *stat, | 286 | buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended) |
353 | struct cbuf *dbufp, int extended) | ||
354 | { | 287 | { |
355 | |||
356 | stat->size = buf_get_int16(bufp); | 288 | stat->size = buf_get_int16(bufp); |
357 | stat->type = buf_get_int16(bufp); | 289 | stat->type = buf_get_int16(bufp); |
358 | stat->dev = buf_get_int32(bufp); | 290 | stat->dev = buf_get_int32(bufp); |
@@ -363,45 +295,17 @@ deserialize_stat(struct cbuf *bufp, struct v9fs_stat *stat, | |||
363 | stat->atime = buf_get_int32(bufp); | 295 | stat->atime = buf_get_int32(bufp); |
364 | stat->mtime = buf_get_int32(bufp); | 296 | stat->mtime = buf_get_int32(bufp); |
365 | stat->length = buf_get_int64(bufp); | 297 | stat->length = buf_get_int64(bufp); |
366 | stat->name = buf_get_stringb(bufp, dbufp); | 298 | buf_get_str(bufp, &stat->name); |
367 | stat->uid = buf_get_stringb(bufp, dbufp); | 299 | buf_get_str(bufp, &stat->uid); |
368 | stat->gid = buf_get_stringb(bufp, dbufp); | 300 | buf_get_str(bufp, &stat->gid); |
369 | stat->muid = buf_get_stringb(bufp, dbufp); | 301 | buf_get_str(bufp, &stat->muid); |
370 | 302 | ||
371 | if (extended) { | 303 | if (extended) { |
372 | stat->extension = buf_get_stringb(bufp, dbufp); | 304 | buf_get_str(bufp, &stat->extension); |
373 | stat->n_uid = buf_get_int32(bufp); | 305 | stat->n_uid = buf_get_int32(bufp); |
374 | stat->n_gid = buf_get_int32(bufp); | 306 | stat->n_gid = buf_get_int32(bufp); |
375 | stat->n_muid = buf_get_int32(bufp); | 307 | stat->n_muid = buf_get_int32(bufp); |
376 | } | 308 | } |
377 | |||
378 | if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) | ||
379 | return 0; | ||
380 | |||
381 | return stat->size + 2; | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * deserialize_statb - wrapper for decoding a received metadata structure | ||
386 | * @bufp: buffer to deserialize | ||
387 | * @dbufp: buffer to deserialize variable strings into | ||
388 | * @extended: non-zero if 9P2000.u | ||
389 | * | ||
390 | */ | ||
391 | |||
392 | static inline struct v9fs_stat *deserialize_statb(struct cbuf *bufp, | ||
393 | struct cbuf *dbufp, | ||
394 | int extended) | ||
395 | { | ||
396 | struct v9fs_stat *ret = buf_alloc(dbufp, sizeof(struct v9fs_stat)); | ||
397 | |||
398 | if (ret) { | ||
399 | int n = deserialize_stat(bufp, ret, dbufp, extended); | ||
400 | if (n <= 0) | ||
401 | return NULL; | ||
402 | } | ||
403 | |||
404 | return ret; | ||
405 | } | 309 | } |
406 | 310 | ||
407 | /** | 311 | /** |
@@ -409,194 +313,27 @@ static inline struct v9fs_stat *deserialize_statb(struct cbuf *bufp, | |||
409 | * @buf: buffer to deserialize | 313 | * @buf: buffer to deserialize |
410 | * @buflen: length of received buffer | 314 | * @buflen: length of received buffer |
411 | * @stat: metadata structure to decode into | 315 | * @stat: metadata structure to decode into |
412 | * @statlen: length of destination metadata structure | ||
413 | * @extended: non-zero if 9P2000.u | 316 | * @extended: non-zero if 9P2000.u |
414 | * | 317 | * |
318 | * Note: stat will point to the buf region. | ||
415 | */ | 319 | */ |
416 | 320 | ||
417 | int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, | 321 | int |
418 | u32 statlen, int extended) | 322 | v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, |
323 | int extended) | ||
419 | { | 324 | { |
420 | struct cbuf buffer; | 325 | struct cbuf buffer; |
421 | struct cbuf *bufp = &buffer; | 326 | struct cbuf *bufp = &buffer; |
422 | struct cbuf dbuffer; | 327 | unsigned char *p; |
423 | struct cbuf *dbufp = &dbuffer; | ||
424 | 328 | ||
425 | buf_init(bufp, buf, buflen); | 329 | buf_init(bufp, buf, buflen); |
426 | buf_init(dbufp, (char *)stat + sizeof(struct v9fs_stat), | 330 | p = bufp->p; |
427 | statlen - sizeof(struct v9fs_stat)); | 331 | buf_get_stat(bufp, stat, extended); |
428 | |||
429 | return deserialize_stat(bufp, stat, dbufp, extended); | ||
430 | } | ||
431 | |||
432 | static inline int v9fs_size_fcall(struct v9fs_fcall *fcall, int extended) | ||
433 | { | ||
434 | int size = 4 + 1 + 2; /* size[4] msg[1] tag[2] */ | ||
435 | int i = 0; | ||
436 | 332 | ||
437 | switch (fcall->id) { | 333 | if (buf_check_overflow(bufp)) |
438 | default: | ||
439 | eprintk(KERN_ERR, "bad msg type %d\n", fcall->id); | ||
440 | return 0; | 334 | return 0; |
441 | case TVERSION: /* msize[4] version[s] */ | 335 | else |
442 | size += 4 + 2 + strlen(fcall->params.tversion.version); | 336 | return bufp->p - p; |
443 | break; | ||
444 | case TAUTH: /* afid[4] uname[s] aname[s] */ | ||
445 | size += 4 + 2 + strlen(fcall->params.tauth.uname) + | ||
446 | 2 + strlen(fcall->params.tauth.aname); | ||
447 | break; | ||
448 | case TFLUSH: /* oldtag[2] */ | ||
449 | size += 2; | ||
450 | break; | ||
451 | case TATTACH: /* fid[4] afid[4] uname[s] aname[s] */ | ||
452 | size += 4 + 4 + 2 + strlen(fcall->params.tattach.uname) + | ||
453 | 2 + strlen(fcall->params.tattach.aname); | ||
454 | break; | ||
455 | case TWALK: /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ | ||
456 | size += 4 + 4 + 2; | ||
457 | /* now compute total for the array of names */ | ||
458 | for (i = 0; i < fcall->params.twalk.nwname; i++) | ||
459 | size += 2 + strlen(fcall->params.twalk.wnames[i]); | ||
460 | break; | ||
461 | case TOPEN: /* fid[4] mode[1] */ | ||
462 | size += 4 + 1; | ||
463 | break; | ||
464 | case TCREATE: /* fid[4] name[s] perm[4] mode[1] */ | ||
465 | size += 4 + 2 + strlen(fcall->params.tcreate.name) + 4 + 1; | ||
466 | break; | ||
467 | case TREAD: /* fid[4] offset[8] count[4] */ | ||
468 | size += 4 + 8 + 4; | ||
469 | break; | ||
470 | case TWRITE: /* fid[4] offset[8] count[4] data[count] */ | ||
471 | size += 4 + 8 + 4 + fcall->params.twrite.count; | ||
472 | break; | ||
473 | case TCLUNK: /* fid[4] */ | ||
474 | size += 4; | ||
475 | break; | ||
476 | case TREMOVE: /* fid[4] */ | ||
477 | size += 4; | ||
478 | break; | ||
479 | case TSTAT: /* fid[4] */ | ||
480 | size += 4; | ||
481 | break; | ||
482 | case TWSTAT: /* fid[4] stat[n] */ | ||
483 | fcall->params.twstat.stat->size = | ||
484 | v9fs_size_stat(fcall->params.twstat.stat, extended); | ||
485 | size += 4 + 2 + 2 + fcall->params.twstat.stat->size; | ||
486 | } | ||
487 | return size; | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * v9fs_serialize_fcall - marshall fcall struct into a packet | ||
492 | * @fcall: structure to convert | ||
493 | * @data: buffer to serialize fcall into | ||
494 | * @datalen: length of buffer to serialize fcall into | ||
495 | * @extended: non-zero if 9P2000.u | ||
496 | * | ||
497 | */ | ||
498 | |||
499 | int | ||
500 | v9fs_serialize_fcall(struct v9fs_fcall *fcall, void *data, u32 datalen, | ||
501 | int extended) | ||
502 | { | ||
503 | int i = 0; | ||
504 | struct v9fs_stat *stat = NULL; | ||
505 | struct cbuf buffer; | ||
506 | struct cbuf *bufp = &buffer; | ||
507 | |||
508 | buf_init(bufp, data, datalen); | ||
509 | |||
510 | if (!fcall) { | ||
511 | eprintk(KERN_ERR, "no fcall\n"); | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | |||
515 | fcall->size = v9fs_size_fcall(fcall, extended); | ||
516 | |||
517 | buf_put_int32(bufp, fcall->size); | ||
518 | buf_put_int8(bufp, fcall->id); | ||
519 | buf_put_int16(bufp, fcall->tag); | ||
520 | |||
521 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", fcall->size, fcall->id, | ||
522 | fcall->tag); | ||
523 | |||
524 | /* now encode it */ | ||
525 | switch (fcall->id) { | ||
526 | default: | ||
527 | eprintk(KERN_ERR, "bad msg type: %d\n", fcall->id); | ||
528 | return -EPROTO; | ||
529 | case TVERSION: | ||
530 | buf_put_int32(bufp, fcall->params.tversion.msize); | ||
531 | buf_put_string(bufp, fcall->params.tversion.version); | ||
532 | break; | ||
533 | case TAUTH: | ||
534 | buf_put_int32(bufp, fcall->params.tauth.afid); | ||
535 | buf_put_string(bufp, fcall->params.tauth.uname); | ||
536 | buf_put_string(bufp, fcall->params.tauth.aname); | ||
537 | break; | ||
538 | case TFLUSH: | ||
539 | buf_put_int16(bufp, fcall->params.tflush.oldtag); | ||
540 | break; | ||
541 | case TATTACH: | ||
542 | buf_put_int32(bufp, fcall->params.tattach.fid); | ||
543 | buf_put_int32(bufp, fcall->params.tattach.afid); | ||
544 | buf_put_string(bufp, fcall->params.tattach.uname); | ||
545 | buf_put_string(bufp, fcall->params.tattach.aname); | ||
546 | break; | ||
547 | case TWALK: | ||
548 | buf_put_int32(bufp, fcall->params.twalk.fid); | ||
549 | buf_put_int32(bufp, fcall->params.twalk.newfid); | ||
550 | buf_put_int16(bufp, fcall->params.twalk.nwname); | ||
551 | for (i = 0; i < fcall->params.twalk.nwname; i++) | ||
552 | buf_put_string(bufp, fcall->params.twalk.wnames[i]); | ||
553 | break; | ||
554 | case TOPEN: | ||
555 | buf_put_int32(bufp, fcall->params.topen.fid); | ||
556 | buf_put_int8(bufp, fcall->params.topen.mode); | ||
557 | break; | ||
558 | case TCREATE: | ||
559 | buf_put_int32(bufp, fcall->params.tcreate.fid); | ||
560 | buf_put_string(bufp, fcall->params.tcreate.name); | ||
561 | buf_put_int32(bufp, fcall->params.tcreate.perm); | ||
562 | buf_put_int8(bufp, fcall->params.tcreate.mode); | ||
563 | break; | ||
564 | case TREAD: | ||
565 | buf_put_int32(bufp, fcall->params.tread.fid); | ||
566 | buf_put_int64(bufp, fcall->params.tread.offset); | ||
567 | buf_put_int32(bufp, fcall->params.tread.count); | ||
568 | break; | ||
569 | case TWRITE: | ||
570 | buf_put_int32(bufp, fcall->params.twrite.fid); | ||
571 | buf_put_int64(bufp, fcall->params.twrite.offset); | ||
572 | buf_put_int32(bufp, fcall->params.twrite.count); | ||
573 | buf_put_data(bufp, fcall->params.twrite.data, | ||
574 | fcall->params.twrite.count); | ||
575 | break; | ||
576 | case TCLUNK: | ||
577 | buf_put_int32(bufp, fcall->params.tclunk.fid); | ||
578 | break; | ||
579 | case TREMOVE: | ||
580 | buf_put_int32(bufp, fcall->params.tremove.fid); | ||
581 | break; | ||
582 | case TSTAT: | ||
583 | buf_put_int32(bufp, fcall->params.tstat.fid); | ||
584 | break; | ||
585 | case TWSTAT: | ||
586 | buf_put_int32(bufp, fcall->params.twstat.fid); | ||
587 | stat = fcall->params.twstat.stat; | ||
588 | |||
589 | buf_put_int16(bufp, stat->size + 2); | ||
590 | serialize_stat(stat, bufp, extended); | ||
591 | break; | ||
592 | } | ||
593 | |||
594 | if (buf_check_overflow(bufp)) { | ||
595 | dprintk(DEBUG_ERROR, "buffer overflow\n"); | ||
596 | return -EIO; | ||
597 | } | ||
598 | |||
599 | return fcall->size; | ||
600 | } | 337 | } |
601 | 338 | ||
602 | /** | 339 | /** |
@@ -611,18 +348,14 @@ v9fs_serialize_fcall(struct v9fs_fcall *fcall, void *data, u32 datalen, | |||
611 | 348 | ||
612 | int | 349 | int |
613 | v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, | 350 | v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, |
614 | int rcalllen, int extended) | 351 | int extended) |
615 | { | 352 | { |
616 | 353 | ||
617 | struct cbuf buffer; | 354 | struct cbuf buffer; |
618 | struct cbuf *bufp = &buffer; | 355 | struct cbuf *bufp = &buffer; |
619 | struct cbuf dbuffer; | ||
620 | struct cbuf *dbufp = &dbuffer; | ||
621 | int i = 0; | 356 | int i = 0; |
622 | 357 | ||
623 | buf_init(bufp, buf, buflen); | 358 | buf_init(bufp, buf, buflen); |
624 | buf_init(dbufp, (char *)rcall + sizeof(struct v9fs_fcall), | ||
625 | rcalllen - sizeof(struct v9fs_fcall)); | ||
626 | 359 | ||
627 | rcall->size = buf_get_int32(bufp); | 360 | rcall->size = buf_get_int32(bufp); |
628 | rcall->id = buf_get_int8(bufp); | 361 | rcall->id = buf_get_int8(bufp); |
@@ -630,13 +363,14 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, | |||
630 | 363 | ||
631 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, | 364 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, |
632 | rcall->tag); | 365 | rcall->tag); |
366 | |||
633 | switch (rcall->id) { | 367 | switch (rcall->id) { |
634 | default: | 368 | default: |
635 | eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); | 369 | eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); |
636 | return -EPROTO; | 370 | return -EPROTO; |
637 | case RVERSION: | 371 | case RVERSION: |
638 | rcall->params.rversion.msize = buf_get_int32(bufp); | 372 | rcall->params.rversion.msize = buf_get_int32(bufp); |
639 | rcall->params.rversion.version = buf_get_stringb(bufp, dbufp); | 373 | buf_get_str(bufp, &rcall->params.rversion.version); |
640 | break; | 374 | break; |
641 | case RFLUSH: | 375 | case RFLUSH: |
642 | break; | 376 | break; |
@@ -647,40 +381,27 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, | |||
647 | break; | 381 | break; |
648 | case RWALK: | 382 | case RWALK: |
649 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); | 383 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); |
650 | if (rcall->params.rwalk.nwqid > 16) { | 384 | if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) { |
651 | eprintk(KERN_ERR, "Rwalk with more than 16 qids: %d\n", | 385 | eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n", |
652 | rcall->params.rwalk.nwqid); | 386 | V9FS_MAXWELEM, rcall->params.rwalk.nwqid); |
653 | return -EPROTO; | 387 | return -EPROTO; |
654 | } | 388 | } |
655 | 389 | ||
656 | rcall->params.rwalk.wqids = buf_alloc(dbufp, | 390 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) |
657 | rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); | 391 | buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); |
658 | if (rcall->params.rwalk.wqids) | ||
659 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) { | ||
660 | rcall->params.rwalk.wqids[i].type = | ||
661 | buf_get_int8(bufp); | ||
662 | rcall->params.rwalk.wqids[i].version = | ||
663 | buf_get_int16(bufp); | ||
664 | rcall->params.rwalk.wqids[i].path = | ||
665 | buf_get_int64(bufp); | ||
666 | } | ||
667 | break; | 392 | break; |
668 | case ROPEN: | 393 | case ROPEN: |
669 | rcall->params.ropen.qid.type = buf_get_int8(bufp); | 394 | buf_get_qid(bufp, &rcall->params.ropen.qid); |
670 | rcall->params.ropen.qid.version = buf_get_int32(bufp); | ||
671 | rcall->params.ropen.qid.path = buf_get_int64(bufp); | ||
672 | rcall->params.ropen.iounit = buf_get_int32(bufp); | 395 | rcall->params.ropen.iounit = buf_get_int32(bufp); |
673 | break; | 396 | break; |
674 | case RCREATE: | 397 | case RCREATE: |
675 | rcall->params.rcreate.qid.type = buf_get_int8(bufp); | 398 | buf_get_qid(bufp, &rcall->params.rcreate.qid); |
676 | rcall->params.rcreate.qid.version = buf_get_int32(bufp); | ||
677 | rcall->params.rcreate.qid.path = buf_get_int64(bufp); | ||
678 | rcall->params.rcreate.iounit = buf_get_int32(bufp); | 399 | rcall->params.rcreate.iounit = buf_get_int32(bufp); |
679 | break; | 400 | break; |
680 | case RREAD: | 401 | case RREAD: |
681 | rcall->params.rread.count = buf_get_int32(bufp); | 402 | rcall->params.rread.count = buf_get_int32(bufp); |
682 | rcall->params.rread.data = buf_get_datab(bufp, dbufp, | 403 | rcall->params.rread.data = bufp->p; |
683 | rcall->params.rread.count); | 404 | buf_check_size(bufp, rcall->params.rread.count); |
684 | break; | 405 | break; |
685 | case RWRITE: | 406 | case RWRITE: |
686 | rcall->params.rwrite.count = buf_get_int32(bufp); | 407 | rcall->params.rwrite.count = buf_get_int32(bufp); |
@@ -691,22 +412,442 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, | |||
691 | break; | 412 | break; |
692 | case RSTAT: | 413 | case RSTAT: |
693 | buf_get_int16(bufp); | 414 | buf_get_int16(bufp); |
694 | rcall->params.rstat.stat = | 415 | buf_get_stat(bufp, &rcall->params.rstat.stat, extended); |
695 | deserialize_statb(bufp, dbufp, extended); | ||
696 | break; | 416 | break; |
697 | case RWSTAT: | 417 | case RWSTAT: |
698 | break; | 418 | break; |
699 | case RERROR: | 419 | case RERROR: |
700 | rcall->params.rerror.error = buf_get_stringb(bufp, dbufp); | 420 | buf_get_str(bufp, &rcall->params.rerror.error); |
701 | if (extended) | 421 | if (extended) |
702 | rcall->params.rerror.errno = buf_get_int16(bufp); | 422 | rcall->params.rerror.errno = buf_get_int16(bufp); |
703 | break; | 423 | break; |
704 | } | 424 | } |
705 | 425 | ||
706 | if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) { | 426 | if (buf_check_overflow(bufp)) { |
707 | dprintk(DEBUG_ERROR, "buffer overflow\n"); | 427 | dprintk(DEBUG_ERROR, "buffer overflow\n"); |
708 | return -EIO; | 428 | return -EIO; |
709 | } | 429 | } |
710 | 430 | ||
711 | return rcall->size; | 431 | return bufp->p - bufp->sp; |
432 | } | ||
433 | |||
434 | static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p) | ||
435 | { | ||
436 | *p = val; | ||
437 | buf_put_int8(bufp, val); | ||
438 | } | ||
439 | |||
440 | static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p) | ||
441 | { | ||
442 | *p = val; | ||
443 | buf_put_int16(bufp, val); | ||
444 | } | ||
445 | |||
446 | static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p) | ||
447 | { | ||
448 | *p = val; | ||
449 | buf_put_int32(bufp, val); | ||
450 | } | ||
451 | |||
452 | static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p) | ||
453 | { | ||
454 | *p = val; | ||
455 | buf_put_int64(bufp, val); | ||
456 | } | ||
457 | |||
458 | static inline void | ||
459 | v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str) | ||
460 | { | ||
461 | if (data) { | ||
462 | str->len = strlen(data); | ||
463 | str->str = bufp->p; | ||
464 | } else { | ||
465 | str->len = 0; | ||
466 | str->str = NULL; | ||
467 | } | ||
468 | |||
469 | buf_put_stringn(bufp, data, str->len); | ||
470 | } | ||
471 | |||
472 | static inline int | ||
473 | v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count, | ||
474 | unsigned char **pdata) | ||
475 | { | ||
476 | *pdata = buf_alloc(bufp, count); | ||
477 | return copy_from_user(*pdata, data, count); | ||
478 | } | ||
479 | |||
480 | static void | ||
481 | v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat, | ||
482 | struct v9fs_stat *stat, int statsz, int extended) | ||
483 | { | ||
484 | v9fs_put_int16(bufp, statsz, &stat->size); | ||
485 | v9fs_put_int16(bufp, wstat->type, &stat->type); | ||
486 | v9fs_put_int32(bufp, wstat->dev, &stat->dev); | ||
487 | v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type); | ||
488 | v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version); | ||
489 | v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path); | ||
490 | v9fs_put_int32(bufp, wstat->mode, &stat->mode); | ||
491 | v9fs_put_int32(bufp, wstat->atime, &stat->atime); | ||
492 | v9fs_put_int32(bufp, wstat->mtime, &stat->mtime); | ||
493 | v9fs_put_int64(bufp, wstat->length, &stat->length); | ||
494 | |||
495 | v9fs_put_str(bufp, wstat->name, &stat->name); | ||
496 | v9fs_put_str(bufp, wstat->uid, &stat->uid); | ||
497 | v9fs_put_str(bufp, wstat->gid, &stat->gid); | ||
498 | v9fs_put_str(bufp, wstat->muid, &stat->muid); | ||
499 | |||
500 | if (extended) { | ||
501 | v9fs_put_str(bufp, wstat->extension, &stat->extension); | ||
502 | v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid); | ||
503 | v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid); | ||
504 | v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid); | ||
505 | } | ||
506 | } | ||
507 | |||
508 | static struct v9fs_fcall * | ||
509 | v9fs_create_common(struct cbuf *bufp, u32 size, u8 id) | ||
510 | { | ||
511 | struct v9fs_fcall *fc; | ||
512 | |||
513 | size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ | ||
514 | fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL); | ||
515 | if (!fc) | ||
516 | return ERR_PTR(-ENOMEM); | ||
517 | |||
518 | fc->sdata = (char *)fc + sizeof(*fc); | ||
519 | |||
520 | buf_init(bufp, (char *)fc->sdata, size); | ||
521 | v9fs_put_int32(bufp, size, &fc->size); | ||
522 | v9fs_put_int8(bufp, id, &fc->id); | ||
523 | v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag); | ||
524 | |||
525 | return fc; | ||
526 | } | ||
527 | |||
528 | void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag) | ||
529 | { | ||
530 | *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); | ||
531 | } | ||
532 | |||
533 | struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version) | ||
534 | { | ||
535 | int size; | ||
536 | struct v9fs_fcall *fc; | ||
537 | struct cbuf buffer; | ||
538 | struct cbuf *bufp = &buffer; | ||
539 | |||
540 | size = 4 + 2 + strlen(version); /* msize[4] version[s] */ | ||
541 | fc = v9fs_create_common(bufp, size, TVERSION); | ||
542 | if (IS_ERR(fc)) | ||
543 | goto error; | ||
544 | |||
545 | v9fs_put_int32(bufp, msize, &fc->params.tversion.msize); | ||
546 | v9fs_put_str(bufp, version, &fc->params.tversion.version); | ||
547 | |||
548 | if (buf_check_overflow(bufp)) { | ||
549 | kfree(fc); | ||
550 | fc = ERR_PTR(-ENOMEM); | ||
551 | } | ||
552 | error: | ||
553 | return fc; | ||
554 | } | ||
555 | |||
556 | struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname) | ||
557 | { | ||
558 | int size; | ||
559 | struct v9fs_fcall *fc; | ||
560 | struct cbuf buffer; | ||
561 | struct cbuf *bufp = &buffer; | ||
562 | |||
563 | size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */ | ||
564 | fc = v9fs_create_common(bufp, size, TAUTH); | ||
565 | if (IS_ERR(fc)) | ||
566 | goto error; | ||
567 | |||
568 | v9fs_put_int32(bufp, afid, &fc->params.tauth.afid); | ||
569 | v9fs_put_str(bufp, uname, &fc->params.tauth.uname); | ||
570 | v9fs_put_str(bufp, aname, &fc->params.tauth.aname); | ||
571 | |||
572 | if (buf_check_overflow(bufp)) { | ||
573 | kfree(fc); | ||
574 | fc = ERR_PTR(-ENOMEM); | ||
575 | } | ||
576 | error: | ||
577 | return fc; | ||
578 | } | ||
579 | |||
580 | struct v9fs_fcall * | ||
581 | v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname) | ||
582 | { | ||
583 | int size; | ||
584 | struct v9fs_fcall *fc; | ||
585 | struct cbuf buffer; | ||
586 | struct cbuf *bufp = &buffer; | ||
587 | |||
588 | size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */ | ||
589 | fc = v9fs_create_common(bufp, size, TATTACH); | ||
590 | if (IS_ERR(fc)) | ||
591 | goto error; | ||
592 | |||
593 | v9fs_put_int32(bufp, fid, &fc->params.tattach.fid); | ||
594 | v9fs_put_int32(bufp, afid, &fc->params.tattach.afid); | ||
595 | v9fs_put_str(bufp, uname, &fc->params.tattach.uname); | ||
596 | v9fs_put_str(bufp, aname, &fc->params.tattach.aname); | ||
597 | |||
598 | error: | ||
599 | return fc; | ||
600 | } | ||
601 | |||
602 | struct v9fs_fcall *v9fs_create_tflush(u16 oldtag) | ||
603 | { | ||
604 | int size; | ||
605 | struct v9fs_fcall *fc; | ||
606 | struct cbuf buffer; | ||
607 | struct cbuf *bufp = &buffer; | ||
608 | |||
609 | size = 2; /* oldtag[2] */ | ||
610 | fc = v9fs_create_common(bufp, size, TFLUSH); | ||
611 | if (IS_ERR(fc)) | ||
612 | goto error; | ||
613 | |||
614 | v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); | ||
615 | |||
616 | if (buf_check_overflow(bufp)) { | ||
617 | kfree(fc); | ||
618 | fc = ERR_PTR(-ENOMEM); | ||
619 | } | ||
620 | error: | ||
621 | return fc; | ||
622 | } | ||
623 | |||
624 | struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname, | ||
625 | char **wnames) | ||
626 | { | ||
627 | int i, size; | ||
628 | struct v9fs_fcall *fc; | ||
629 | struct cbuf buffer; | ||
630 | struct cbuf *bufp = &buffer; | ||
631 | |||
632 | if (nwname > V9FS_MAXWELEM) { | ||
633 | dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM); | ||
634 | return NULL; | ||
635 | } | ||
636 | |||
637 | size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ | ||
638 | for (i = 0; i < nwname; i++) { | ||
639 | size += 2 + strlen(wnames[i]); /* wname[s] */ | ||
640 | } | ||
641 | |||
642 | fc = v9fs_create_common(bufp, size, TWALK); | ||
643 | if (IS_ERR(fc)) | ||
644 | goto error; | ||
645 | |||
646 | v9fs_put_int32(bufp, fid, &fc->params.twalk.fid); | ||
647 | v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid); | ||
648 | v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname); | ||
649 | for (i = 0; i < nwname; i++) { | ||
650 | v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); | ||
651 | } | ||
652 | |||
653 | if (buf_check_overflow(bufp)) { | ||
654 | kfree(fc); | ||
655 | fc = ERR_PTR(-ENOMEM); | ||
656 | } | ||
657 | error: | ||
658 | return fc; | ||
659 | } | ||
660 | |||
661 | struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode) | ||
662 | { | ||
663 | int size; | ||
664 | struct v9fs_fcall *fc; | ||
665 | struct cbuf buffer; | ||
666 | struct cbuf *bufp = &buffer; | ||
667 | |||
668 | size = 4 + 1; /* fid[4] mode[1] */ | ||
669 | fc = v9fs_create_common(bufp, size, TOPEN); | ||
670 | if (IS_ERR(fc)) | ||
671 | goto error; | ||
672 | |||
673 | v9fs_put_int32(bufp, fid, &fc->params.topen.fid); | ||
674 | v9fs_put_int8(bufp, mode, &fc->params.topen.mode); | ||
675 | |||
676 | if (buf_check_overflow(bufp)) { | ||
677 | kfree(fc); | ||
678 | fc = ERR_PTR(-ENOMEM); | ||
679 | } | ||
680 | error: | ||
681 | return fc; | ||
682 | } | ||
683 | |||
684 | struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode) | ||
685 | { | ||
686 | int size; | ||
687 | struct v9fs_fcall *fc; | ||
688 | struct cbuf buffer; | ||
689 | struct cbuf *bufp = &buffer; | ||
690 | |||
691 | size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */ | ||
692 | fc = v9fs_create_common(bufp, size, TCREATE); | ||
693 | if (IS_ERR(fc)) | ||
694 | goto error; | ||
695 | |||
696 | v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid); | ||
697 | v9fs_put_str(bufp, name, &fc->params.tcreate.name); | ||
698 | v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm); | ||
699 | v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode); | ||
700 | |||
701 | if (buf_check_overflow(bufp)) { | ||
702 | kfree(fc); | ||
703 | fc = ERR_PTR(-ENOMEM); | ||
704 | } | ||
705 | error: | ||
706 | return fc; | ||
707 | } | ||
708 | |||
709 | struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count) | ||
710 | { | ||
711 | int size; | ||
712 | struct v9fs_fcall *fc; | ||
713 | struct cbuf buffer; | ||
714 | struct cbuf *bufp = &buffer; | ||
715 | |||
716 | size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ | ||
717 | fc = v9fs_create_common(bufp, size, TREAD); | ||
718 | if (IS_ERR(fc)) | ||
719 | goto error; | ||
720 | |||
721 | v9fs_put_int32(bufp, fid, &fc->params.tread.fid); | ||
722 | v9fs_put_int64(bufp, offset, &fc->params.tread.offset); | ||
723 | v9fs_put_int32(bufp, count, &fc->params.tread.count); | ||
724 | |||
725 | if (buf_check_overflow(bufp)) { | ||
726 | kfree(fc); | ||
727 | fc = ERR_PTR(-ENOMEM); | ||
728 | } | ||
729 | error: | ||
730 | return fc; | ||
731 | } | ||
732 | |||
733 | struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count, | ||
734 | const char __user * data) | ||
735 | { | ||
736 | int size, err; | ||
737 | struct v9fs_fcall *fc; | ||
738 | struct cbuf buffer; | ||
739 | struct cbuf *bufp = &buffer; | ||
740 | |||
741 | size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */ | ||
742 | fc = v9fs_create_common(bufp, size, TWRITE); | ||
743 | if (IS_ERR(fc)) | ||
744 | goto error; | ||
745 | |||
746 | v9fs_put_int32(bufp, fid, &fc->params.twrite.fid); | ||
747 | v9fs_put_int64(bufp, offset, &fc->params.twrite.offset); | ||
748 | v9fs_put_int32(bufp, count, &fc->params.twrite.count); | ||
749 | err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data); | ||
750 | if (err) { | ||
751 | kfree(fc); | ||
752 | fc = ERR_PTR(err); | ||
753 | } | ||
754 | |||
755 | if (buf_check_overflow(bufp)) { | ||
756 | kfree(fc); | ||
757 | fc = ERR_PTR(-ENOMEM); | ||
758 | } | ||
759 | error: | ||
760 | return fc; | ||
761 | } | ||
762 | |||
763 | struct v9fs_fcall *v9fs_create_tclunk(u32 fid) | ||
764 | { | ||
765 | int size; | ||
766 | struct v9fs_fcall *fc; | ||
767 | struct cbuf buffer; | ||
768 | struct cbuf *bufp = &buffer; | ||
769 | |||
770 | size = 4; /* fid[4] */ | ||
771 | fc = v9fs_create_common(bufp, size, TCLUNK); | ||
772 | if (IS_ERR(fc)) | ||
773 | goto error; | ||
774 | |||
775 | v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid); | ||
776 | |||
777 | if (buf_check_overflow(bufp)) { | ||
778 | kfree(fc); | ||
779 | fc = ERR_PTR(-ENOMEM); | ||
780 | } | ||
781 | error: | ||
782 | return fc; | ||
783 | } | ||
784 | |||
785 | struct v9fs_fcall *v9fs_create_tremove(u32 fid) | ||
786 | { | ||
787 | int size; | ||
788 | struct v9fs_fcall *fc; | ||
789 | struct cbuf buffer; | ||
790 | struct cbuf *bufp = &buffer; | ||
791 | |||
792 | size = 4; /* fid[4] */ | ||
793 | fc = v9fs_create_common(bufp, size, TREMOVE); | ||
794 | if (IS_ERR(fc)) | ||
795 | goto error; | ||
796 | |||
797 | v9fs_put_int32(bufp, fid, &fc->params.tremove.fid); | ||
798 | |||
799 | if (buf_check_overflow(bufp)) { | ||
800 | kfree(fc); | ||
801 | fc = ERR_PTR(-ENOMEM); | ||
802 | } | ||
803 | error: | ||
804 | return fc; | ||
805 | } | ||
806 | |||
807 | struct v9fs_fcall *v9fs_create_tstat(u32 fid) | ||
808 | { | ||
809 | int size; | ||
810 | struct v9fs_fcall *fc; | ||
811 | struct cbuf buffer; | ||
812 | struct cbuf *bufp = &buffer; | ||
813 | |||
814 | size = 4; /* fid[4] */ | ||
815 | fc = v9fs_create_common(bufp, size, TSTAT); | ||
816 | if (IS_ERR(fc)) | ||
817 | goto error; | ||
818 | |||
819 | v9fs_put_int32(bufp, fid, &fc->params.tstat.fid); | ||
820 | |||
821 | if (buf_check_overflow(bufp)) { | ||
822 | kfree(fc); | ||
823 | fc = ERR_PTR(-ENOMEM); | ||
824 | } | ||
825 | error: | ||
826 | return fc; | ||
827 | } | ||
828 | |||
829 | struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat, | ||
830 | int extended) | ||
831 | { | ||
832 | int size, statsz; | ||
833 | struct v9fs_fcall *fc; | ||
834 | struct cbuf buffer; | ||
835 | struct cbuf *bufp = &buffer; | ||
836 | |||
837 | statsz = v9fs_size_wstat(wstat, extended); | ||
838 | size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ | ||
839 | fc = v9fs_create_common(bufp, size, TWSTAT); | ||
840 | if (IS_ERR(fc)) | ||
841 | goto error; | ||
842 | |||
843 | v9fs_put_int32(bufp, fid, &fc->params.twstat.fid); | ||
844 | buf_put_int16(bufp, statsz + 2); | ||
845 | v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended); | ||
846 | |||
847 | if (buf_check_overflow(bufp)) { | ||
848 | kfree(fc); | ||
849 | fc = ERR_PTR(-ENOMEM); | ||
850 | } | ||
851 | error: | ||
852 | return fc; | ||
712 | } | 853 | } |