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