diff options
author | Eric Van Hensbergen <ericvh@gmail.com> | 2008-10-16 09:30:07 -0400 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@gmail.com> | 2008-10-17 12:04:45 -0400 |
commit | 51a87c552dfd428e304c865e24ecbe091556f226 (patch) | |
tree | 6e9012962e6601b559dcf15ae3228647a8581a31 /net/9p/client.c | |
parent | cb198131b0e7aba755ac164744536d461e86ab82 (diff) |
9p: rework client code to use new protocol support functions
Now that the new protocol functions are in place, this patch switches
the client code to using the new support code.
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
Diffstat (limited to 'net/9p/client.c')
-rw-r--r-- | net/9p/client.c | 931 |
1 files changed, 454 insertions, 477 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index 6004fded6682..2a166bfb95a3 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/parser.h> | 35 | #include <linux/parser.h> |
36 | #include <net/9p/client.h> | 36 | #include <net/9p/client.h> |
37 | #include <net/9p/transport.h> | 37 | #include <net/9p/transport.h> |
38 | #include "protocol.h" | ||
38 | 39 | ||
39 | /* | 40 | /* |
40 | * Client Option Parsing (code inspired by NFS code) | 41 | * Client Option Parsing (code inspired by NFS code) |
@@ -55,8 +56,8 @@ static const match_table_t tokens = { | |||
55 | {Opt_err, NULL}, | 56 | {Opt_err, NULL}, |
56 | }; | 57 | }; |
57 | 58 | ||
58 | static int | 59 | static struct p9_req_t * |
59 | p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc); | 60 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); |
60 | 61 | ||
61 | /** | 62 | /** |
62 | * v9fs_parse_options - parse mount options into session structure | 63 | * v9fs_parse_options - parse mount options into session structure |
@@ -138,10 +139,11 @@ static int parse_opts(char *opts, struct p9_client *clnt) | |||
138 | * | 139 | * |
139 | */ | 140 | */ |
140 | 141 | ||
141 | struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | 142 | static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) |
142 | { | 143 | { |
143 | unsigned long flags; | 144 | unsigned long flags; |
144 | int row, col; | 145 | int row, col; |
146 | struct p9_req_t *req; | ||
145 | 147 | ||
146 | /* This looks up the original request by tag so we know which | 148 | /* This looks up the original request by tag so we know which |
147 | * buffer to read the data into */ | 149 | * buffer to read the data into */ |
@@ -157,19 +159,11 @@ struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
157 | 159 | ||
158 | if (!c->reqs[row]) { | 160 | if (!c->reqs[row]) { |
159 | printk(KERN_ERR "Couldn't grow tag array\n"); | 161 | printk(KERN_ERR "Couldn't grow tag array\n"); |
160 | BUG(); | 162 | return ERR_PTR(-ENOMEM); |
161 | } | 163 | } |
162 | for (col = 0; col < P9_ROW_MAXTAG; col++) { | 164 | for (col = 0; col < P9_ROW_MAXTAG; col++) { |
163 | c->reqs[row][col].status = REQ_STATUS_IDLE; | 165 | c->reqs[row][col].status = REQ_STATUS_IDLE; |
164 | c->reqs[row][col].flush_tag = P9_NOTAG; | 166 | c->reqs[row][col].tc = NULL; |
165 | c->reqs[row][col].wq = kmalloc( | ||
166 | sizeof(wait_queue_head_t), GFP_ATOMIC); | ||
167 | if (!c->reqs[row][col].wq) { | ||
168 | printk(KERN_ERR | ||
169 | "Couldn't grow tag array\n"); | ||
170 | BUG(); | ||
171 | } | ||
172 | init_waitqueue_head(c->reqs[row][col].wq); | ||
173 | } | 167 | } |
174 | c->max_tag += P9_ROW_MAXTAG; | 168 | c->max_tag += P9_ROW_MAXTAG; |
175 | } | 169 | } |
@@ -178,12 +172,39 @@ struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
178 | row = tag / P9_ROW_MAXTAG; | 172 | row = tag / P9_ROW_MAXTAG; |
179 | col = tag % P9_ROW_MAXTAG; | 173 | col = tag % P9_ROW_MAXTAG; |
180 | 174 | ||
181 | c->reqs[row][col].status = REQ_STATUS_ALLOC; | 175 | req = &c->reqs[row][col]; |
182 | c->reqs[row][col].flush_tag = P9_NOTAG; | 176 | if (!req->tc) { |
177 | req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); | ||
178 | if (!req->wq) { | ||
179 | printk(KERN_ERR "Couldn't grow tag array\n"); | ||
180 | return ERR_PTR(-ENOMEM); | ||
181 | } | ||
182 | init_waitqueue_head(req->wq); | ||
183 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
184 | GFP_KERNEL); | ||
185 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
186 | GFP_KERNEL); | ||
187 | if ((!req->tc) || (!req->rc)) { | ||
188 | printk(KERN_ERR "Couldn't grow tag array\n"); | ||
189 | kfree(req->tc); | ||
190 | kfree(req->rc); | ||
191 | return ERR_PTR(-ENOMEM); | ||
192 | } | ||
193 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); | ||
194 | req->tc->capacity = c->msize; | ||
195 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); | ||
196 | req->rc->capacity = c->msize; | ||
197 | } | ||
198 | |||
199 | p9pdu_reset(req->tc); | ||
200 | p9pdu_reset(req->rc); | ||
201 | |||
202 | req->flush_tag = 0; | ||
203 | req->tc->tag = tag-1; | ||
204 | req->status = REQ_STATUS_ALLOC; | ||
183 | 205 | ||
184 | return &c->reqs[row][col]; | 206 | return &c->reqs[row][col]; |
185 | } | 207 | } |
186 | EXPORT_SYMBOL(p9_tag_alloc); | ||
187 | 208 | ||
188 | /** | 209 | /** |
189 | * p9_tag_lookup - lookup a request by tag | 210 | * p9_tag_lookup - lookup a request by tag |
@@ -264,59 +285,34 @@ static void p9_tag_cleanup(struct p9_client *c) | |||
264 | 285 | ||
265 | /* free requests associated with tags */ | 286 | /* free requests associated with tags */ |
266 | for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { | 287 | for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { |
267 | for (col = 0; col < P9_ROW_MAXTAG; col++) | 288 | for (col = 0; col < P9_ROW_MAXTAG; col++) { |
268 | kfree(c->reqs[row][col].wq); | 289 | kfree(c->reqs[row][col].wq); |
290 | kfree(c->reqs[row][col].tc); | ||
291 | kfree(c->reqs[row][col].rc); | ||
292 | } | ||
269 | kfree(c->reqs[row]); | 293 | kfree(c->reqs[row]); |
270 | } | 294 | } |
271 | c->max_tag = 0; | 295 | c->max_tag = 0; |
272 | } | 296 | } |
273 | 297 | ||
274 | /** | 298 | /** |
275 | * p9_client_flush - flush (cancel) a request | ||
276 | * c: client state | ||
277 | * req: request to cancel | ||
278 | * | ||
279 | * This sents a flush for a particular requests and links | ||
280 | * the flush request to the original request. The current | ||
281 | * code only supports a single flush request although the protocol | ||
282 | * allows for multiple flush requests to be sent for a single request. | ||
283 | * | ||
284 | */ | ||
285 | |||
286 | static int p9_client_flush(struct p9_client *c, struct p9_req_t *req) | ||
287 | { | ||
288 | struct p9_fcall *tc, *rc = NULL; | ||
289 | int err; | ||
290 | |||
291 | P9_DPRINTK(P9_DEBUG_9P, "client %p tag %d\n", c, req->tc->tag); | ||
292 | |||
293 | tc = p9_create_tflush(req->tc->tag); | ||
294 | if (IS_ERR(tc)) | ||
295 | return PTR_ERR(tc); | ||
296 | |||
297 | err = p9_client_rpc(c, tc, &rc); | ||
298 | |||
299 | /* we don't free anything here because RPC isn't complete */ | ||
300 | |||
301 | return err; | ||
302 | } | ||
303 | |||
304 | /** | ||
305 | * p9_free_req - free a request and clean-up as necessary | 299 | * p9_free_req - free a request and clean-up as necessary |
306 | * c: client state | 300 | * c: client state |
307 | * r: request to release | 301 | * r: request to release |
308 | * | 302 | * |
309 | */ | 303 | */ |
310 | 304 | ||
311 | void p9_free_req(struct p9_client *c, struct p9_req_t *r) | 305 | static void p9_free_req(struct p9_client *c, struct p9_req_t *r) |
312 | { | 306 | { |
313 | r->flush_tag = P9_NOTAG; | 307 | int tag = r->tc->tag; |
308 | P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag); | ||
309 | |||
314 | r->status = REQ_STATUS_IDLE; | 310 | r->status = REQ_STATUS_IDLE; |
315 | if (r->tc->tag != P9_NOTAG && p9_idpool_check(r->tc->tag, c->tagpool)) | 311 | if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool)) |
316 | p9_idpool_put(r->tc->tag, c->tagpool); | 312 | p9_idpool_put(tag, c->tagpool); |
317 | 313 | ||
318 | /* if this was a flush request we have to free response fcall */ | 314 | /* if this was a flush request we have to free response fcall */ |
319 | if (r->tc->id == P9_TFLUSH) { | 315 | if (r->rc->id == P9_RFLUSH) { |
320 | kfree(r->tc); | 316 | kfree(r->tc); |
321 | kfree(r->rc); | 317 | kfree(r->rc); |
322 | } | 318 | } |
@@ -333,30 +329,28 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req) | |||
333 | struct p9_req_t *other_req; | 329 | struct p9_req_t *other_req; |
334 | unsigned long flags; | 330 | unsigned long flags; |
335 | 331 | ||
336 | P9_DPRINTK(P9_DEBUG_MUX, ": %d\n", req->tc->tag); | 332 | P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag); |
337 | 333 | ||
338 | if (req->status == REQ_STATUS_ERROR) | 334 | if (req->status == REQ_STATUS_ERROR) |
339 | wake_up(req->wq); | 335 | wake_up(req->wq); |
340 | 336 | ||
341 | if (req->tc->id == P9_TFLUSH) { /* flush receive path */ | 337 | if (req->flush_tag) { /* flush receive path */ |
342 | P9_DPRINTK(P9_DEBUG_MUX, "flush: %d\n", req->tc->tag); | 338 | P9_DPRINTK(P9_DEBUG_9P, "<<< RFLUSH %d\n", req->tc->tag); |
343 | spin_lock_irqsave(&c->lock, flags); | 339 | spin_lock_irqsave(&c->lock, flags); |
344 | other_req = p9_tag_lookup(c, req->tc->params.tflush.oldtag); | 340 | other_req = p9_tag_lookup(c, req->flush_tag); |
345 | if (other_req->flush_tag != req->tc->tag) /* stale flush */ | 341 | if (other_req->status != REQ_STATUS_FLSH) /* stale flush */ |
346 | spin_unlock_irqrestore(&c->lock, flags); | 342 | spin_unlock_irqrestore(&c->lock, flags); |
347 | else { | 343 | else { |
348 | BUG_ON(other_req->status != REQ_STATUS_FLSH); | ||
349 | other_req->status = REQ_STATUS_FLSHD; | 344 | other_req->status = REQ_STATUS_FLSHD; |
350 | spin_unlock_irqrestore(&c->lock, flags); | 345 | spin_unlock_irqrestore(&c->lock, flags); |
351 | wake_up(other_req->wq); | 346 | wake_up(other_req->wq); |
352 | } | 347 | } |
353 | p9_free_req(c, req); | 348 | p9_free_req(c, req); |
354 | } else { /* normal receive path */ | 349 | } else { /* normal receive path */ |
355 | P9_DPRINTK(P9_DEBUG_MUX, "normal: %d\n", req->tc->tag); | 350 | P9_DPRINTK(P9_DEBUG_MUX, "normal: tag %d\n", req->tc->tag); |
356 | spin_lock_irqsave(&c->lock, flags); | 351 | spin_lock_irqsave(&c->lock, flags); |
357 | if (req->status != REQ_STATUS_FLSHD) | 352 | if (req->status != REQ_STATUS_FLSHD) |
358 | req->status = REQ_STATUS_RCVD; | 353 | req->status = REQ_STATUS_RCVD; |
359 | req->flush_tag = P9_NOTAG; | ||
360 | spin_unlock_irqrestore(&c->lock, flags); | 354 | spin_unlock_irqrestore(&c->lock, flags); |
361 | wake_up(req->wq); | 355 | wake_up(req->wq); |
362 | P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); | 356 | P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); |
@@ -365,28 +359,164 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req) | |||
365 | EXPORT_SYMBOL(p9_client_cb); | 359 | EXPORT_SYMBOL(p9_client_cb); |
366 | 360 | ||
367 | /** | 361 | /** |
362 | * p9_parse_header - parse header arguments out of a packet | ||
363 | * @pdu: packet to parse | ||
364 | * @size: size of packet | ||
365 | * @type: type of request | ||
366 | * @tag: tag of packet | ||
367 | * @rewind: set if we need to rewind offset afterwards | ||
368 | */ | ||
369 | |||
370 | int | ||
371 | p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag, | ||
372 | int rewind) | ||
373 | { | ||
374 | int8_t r_type; | ||
375 | int16_t r_tag; | ||
376 | int32_t r_size; | ||
377 | int offset = pdu->offset; | ||
378 | int err; | ||
379 | |||
380 | pdu->offset = 0; | ||
381 | if (pdu->size == 0) | ||
382 | pdu->size = 7; | ||
383 | |||
384 | err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag); | ||
385 | if (err) | ||
386 | goto rewind_and_exit; | ||
387 | |||
388 | pdu->size = r_size; | ||
389 | pdu->id = r_type; | ||
390 | pdu->tag = r_tag; | ||
391 | |||
392 | P9_DPRINTK(P9_DEBUG_MUX, "pdu: type: %d tag: %d size=%d offset=%d\n", | ||
393 | pdu->id, pdu->tag, pdu->size, pdu->offset); | ||
394 | |||
395 | if (type) | ||
396 | *type = r_type; | ||
397 | if (tag) | ||
398 | *tag = r_tag; | ||
399 | if (size) | ||
400 | *size = r_size; | ||
401 | |||
402 | |||
403 | rewind_and_exit: | ||
404 | if (rewind) | ||
405 | pdu->offset = offset; | ||
406 | return err; | ||
407 | } | ||
408 | EXPORT_SYMBOL(p9_parse_header); | ||
409 | |||
410 | /** | ||
411 | * p9_check_errors - check 9p packet for error return and process it | ||
412 | * @c: current client instance | ||
413 | * @req: request to parse and check for error conditions | ||
414 | * | ||
415 | * returns error code if one is discovered, otherwise returns 0 | ||
416 | * | ||
417 | * this will have to be more complicated if we have multiple | ||
418 | * error packet types | ||
419 | */ | ||
420 | |||
421 | static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | ||
422 | { | ||
423 | int8_t type; | ||
424 | int err; | ||
425 | |||
426 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); | ||
427 | if (err) { | ||
428 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); | ||
429 | return err; | ||
430 | } | ||
431 | |||
432 | if (type == P9_RERROR) { | ||
433 | int ecode; | ||
434 | char *ename; | ||
435 | |||
436 | err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); | ||
437 | if (err) { | ||
438 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", | ||
439 | err); | ||
440 | return err; | ||
441 | } | ||
442 | |||
443 | if (c->dotu) | ||
444 | err = -ecode; | ||
445 | |||
446 | if (!err) { | ||
447 | err = p9_errstr2errno(ename, strlen(ename)); | ||
448 | |||
449 | /* string match failed */ | ||
450 | if (!err) | ||
451 | err = -ESERVERFAULT; | ||
452 | } | ||
453 | |||
454 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | ||
455 | |||
456 | kfree(ename); | ||
457 | } else | ||
458 | err = 0; | ||
459 | |||
460 | return err; | ||
461 | } | ||
462 | |||
463 | /** | ||
464 | * p9_client_flush - flush (cancel) a request | ||
465 | * c: client state | ||
466 | * req: request to cancel | ||
467 | * | ||
468 | * This sents a flush for a particular requests and links | ||
469 | * the flush request to the original request. The current | ||
470 | * code only supports a single flush request although the protocol | ||
471 | * allows for multiple flush requests to be sent for a single request. | ||
472 | * | ||
473 | */ | ||
474 | |||
475 | static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) | ||
476 | { | ||
477 | struct p9_req_t *req; | ||
478 | int16_t oldtag; | ||
479 | int err; | ||
480 | |||
481 | err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1); | ||
482 | if (err) | ||
483 | return err; | ||
484 | |||
485 | P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag); | ||
486 | |||
487 | req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag); | ||
488 | if (IS_ERR(req)) | ||
489 | return PTR_ERR(req); | ||
490 | |||
491 | req->flush_tag = oldtag; | ||
492 | |||
493 | /* we don't free anything here because RPC isn't complete */ | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | /** | ||
368 | * p9_client_rpc - issue a request and wait for a response | 498 | * p9_client_rpc - issue a request and wait for a response |
369 | * @c: client session | 499 | * @c: client session |
370 | * @tc: &p9_fcall request to transmit | 500 | * @type: type of request |
371 | * @rc: &p9_fcall to put reponse into | 501 | * @fmt: protocol format string (see protocol.c) |
372 | * | 502 | * |
373 | * Returns 0 on success, error code on failure | 503 | * Returns request structure (which client must free using p9_free_req) |
374 | */ | 504 | */ |
375 | 505 | ||
376 | static int | 506 | static struct p9_req_t * |
377 | p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) | 507 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) |
378 | { | 508 | { |
379 | int tag, err, size; | 509 | va_list ap; |
380 | char *rdata; | 510 | int tag, err; |
381 | struct p9_req_t *req; | 511 | struct p9_req_t *req; |
382 | unsigned long flags; | 512 | unsigned long flags; |
383 | int sigpending; | 513 | int sigpending; |
384 | int flushed = 0; | 514 | int flushed = 0; |
385 | 515 | ||
386 | P9_DPRINTK(P9_DEBUG_9P, "client %p tc %p rc %p\n", c, tc, rc); | 516 | P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); |
387 | 517 | ||
388 | if (c->status != Connected) | 518 | if (c->status != Connected) |
389 | return -EIO; | 519 | return ERR_PTR(-EIO); |
390 | 520 | ||
391 | if (signal_pending(current)) { | 521 | if (signal_pending(current)) { |
392 | sigpending = 1; | 522 | sigpending = 1; |
@@ -395,50 +525,22 @@ p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) | |||
395 | sigpending = 0; | 525 | sigpending = 0; |
396 | 526 | ||
397 | tag = P9_NOTAG; | 527 | tag = P9_NOTAG; |
398 | if (tc->id != P9_TVERSION) { | 528 | if (type != P9_TVERSION) { |
399 | tag = p9_idpool_get(c->tagpool); | 529 | tag = p9_idpool_get(c->tagpool); |
400 | if (tag < 0) | 530 | if (tag < 0) |
401 | return -ENOMEM; | 531 | return ERR_PTR(-ENOMEM); |
402 | } | 532 | } |
403 | 533 | ||
404 | req = p9_tag_alloc(c, tag); | 534 | req = p9_tag_alloc(c, tag); |
535 | if (IS_ERR(req)) | ||
536 | return req; | ||
405 | 537 | ||
406 | /* if this is a flush request, backlink flush request now to | 538 | /* marshall the data */ |
407 | * avoid race conditions later. */ | 539 | p9pdu_prepare(req->tc, tag, type); |
408 | if (tc->id == P9_TFLUSH) { | 540 | va_start(ap, fmt); |
409 | struct p9_req_t *other_req = | 541 | err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap); |
410 | p9_tag_lookup(c, tc->params.tflush.oldtag); | 542 | va_end(ap); |
411 | if (other_req->status == REQ_STATUS_FLSH) | 543 | p9pdu_finalize(req->tc); |
412 | other_req->flush_tag = tag; | ||
413 | } | ||
414 | |||
415 | p9_set_tag(tc, tag); | ||
416 | |||
417 | /* | ||
418 | * if client passed in a pre-allocated response fcall struct | ||
419 | * then we just use that, otherwise we allocate one. | ||
420 | */ | ||
421 | |||
422 | if (rc == NULL) | ||
423 | req->rc = NULL; | ||
424 | else | ||
425 | req->rc = *rc; | ||
426 | if (req->rc == NULL) { | ||
427 | req->rc = kmalloc(sizeof(struct p9_fcall) + c->msize, | ||
428 | GFP_KERNEL); | ||
429 | if (!req->rc) { | ||
430 | err = -ENOMEM; | ||
431 | p9_idpool_put(tag, c->tagpool); | ||
432 | p9_free_req(c, req); | ||
433 | goto reterr; | ||
434 | } | ||
435 | *rc = req->rc; | ||
436 | } | ||
437 | |||
438 | rdata = (char *)req->rc+sizeof(struct p9_fcall); | ||
439 | |||
440 | req->tc = tc; | ||
441 | P9_DPRINTK(P9_DEBUG_9P, "request: tc: %p rc: %p\n", req->tc, req->rc); | ||
442 | 544 | ||
443 | err = c->trans_mod->request(c, req); | 545 | err = c->trans_mod->request(c, req); |
444 | if (err < 0) { | 546 | if (err < 0) { |
@@ -447,28 +549,28 @@ p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) | |||
447 | } | 549 | } |
448 | 550 | ||
449 | /* if it was a flush we just transmitted, return our tag */ | 551 | /* if it was a flush we just transmitted, return our tag */ |
450 | if (tc->id == P9_TFLUSH) | 552 | if (type == P9_TFLUSH) |
451 | return 0; | 553 | return req; |
452 | again: | 554 | again: |
453 | P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d\n", req->wq, tag); | 555 | P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag); |
454 | err = wait_event_interruptible(*req->wq, | 556 | err = wait_event_interruptible(*req->wq, |
455 | req->status >= REQ_STATUS_RCVD); | 557 | req->status >= REQ_STATUS_RCVD); |
456 | P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d returned %d (flushed=%d)\n", | 558 | P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d (flushed=%d)\n", |
457 | req->wq, tag, err, flushed); | 559 | req->wq, tag, err, flushed); |
458 | 560 | ||
459 | if (req->status == REQ_STATUS_ERROR) { | 561 | if (req->status == REQ_STATUS_ERROR) { |
460 | P9_DPRINTK(P9_DEBUG_9P, "req_status error %d\n", req->t_err); | 562 | P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); |
461 | err = req->t_err; | 563 | err = req->t_err; |
462 | } else if (err == -ERESTARTSYS && flushed) { | 564 | } else if (err == -ERESTARTSYS && flushed) { |
463 | P9_DPRINTK(P9_DEBUG_9P, "flushed - going again\n"); | 565 | P9_DPRINTK(P9_DEBUG_MUX, "flushed - going again\n"); |
464 | goto again; | 566 | goto again; |
465 | } else if (req->status == REQ_STATUS_FLSHD) { | 567 | } else if (req->status == REQ_STATUS_FLSHD) { |
466 | P9_DPRINTK(P9_DEBUG_9P, "flushed - erestartsys\n"); | 568 | P9_DPRINTK(P9_DEBUG_MUX, "flushed - erestartsys\n"); |
467 | err = -ERESTARTSYS; | 569 | err = -ERESTARTSYS; |
468 | } | 570 | } |
469 | 571 | ||
470 | if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) { | 572 | if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) { |
471 | P9_DPRINTK(P9_DEBUG_9P, "flushing\n"); | 573 | P9_DPRINTK(P9_DEBUG_MUX, "flushing\n"); |
472 | spin_lock_irqsave(&c->lock, flags); | 574 | spin_lock_irqsave(&c->lock, flags); |
473 | if (req->status == REQ_STATUS_SENT) | 575 | if (req->status == REQ_STATUS_SENT) |
474 | req->status = REQ_STATUS_FLSH; | 576 | req->status = REQ_STATUS_FLSH; |
@@ -493,42 +595,17 @@ again: | |||
493 | if (err < 0) | 595 | if (err < 0) |
494 | goto reterr; | 596 | goto reterr; |
495 | 597 | ||
496 | size = le32_to_cpu(*(__le32 *) rdata); | 598 | err = p9_check_errors(c, req); |
497 | 599 | if (!err) { | |
498 | err = p9_deserialize_fcall(rdata, size, req->rc, c->dotu); | 600 | P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type); |
499 | if (err < 0) { | 601 | return req; |
500 | P9_DPRINTK(P9_DEBUG_9P, | ||
501 | "9p debug: client rpc deserialize returned %d\n", err); | ||
502 | goto reterr; | ||
503 | } | 602 | } |
504 | 603 | ||
505 | if (req->rc->id == P9_RERROR) { | ||
506 | int ecode = req->rc->params.rerror.errno; | ||
507 | struct p9_str *ename = &req->rc->params.rerror.error; | ||
508 | |||
509 | P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, | ||
510 | ename->str); | ||
511 | |||
512 | if (c->dotu) | ||
513 | err = -ecode; | ||
514 | |||
515 | if (!err) { | ||
516 | err = p9_errstr2errno(ename->str, ename->len); | ||
517 | |||
518 | /* string match failed */ | ||
519 | if (!err) { | ||
520 | PRINT_FCALL_ERROR("unknown error", req->rc); | ||
521 | err = -ESERVERFAULT; | ||
522 | } | ||
523 | } | ||
524 | } else | ||
525 | err = 0; | ||
526 | |||
527 | reterr: | 604 | reterr: |
605 | P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type, | ||
606 | err); | ||
528 | p9_free_req(c, req); | 607 | p9_free_req(c, req); |
529 | 608 | return ERR_PTR(err); | |
530 | P9_DPRINTK(P9_DEBUG_9P, "returning %d\n", err); | ||
531 | return err; | ||
532 | } | 609 | } |
533 | 610 | ||
534 | static struct p9_fid *p9_fid_create(struct p9_client *clnt) | 611 | static struct p9_fid *p9_fid_create(struct p9_client *clnt) |
@@ -536,7 +613,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt) | |||
536 | int err; | 613 | int err; |
537 | struct p9_fid *fid; | 614 | struct p9_fid *fid; |
538 | 615 | ||
539 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); | 616 | P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt); |
540 | fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); | 617 | fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); |
541 | if (!fid) | 618 | if (!fid) |
542 | return ERR_PTR(-ENOMEM); | 619 | return ERR_PTR(-ENOMEM); |
@@ -569,7 +646,7 @@ static void p9_fid_destroy(struct p9_fid *fid) | |||
569 | { | 646 | { |
570 | struct p9_client *clnt; | 647 | struct p9_client *clnt; |
571 | 648 | ||
572 | P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); | 649 | P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid); |
573 | clnt = fid->clnt; | 650 | clnt = fid->clnt; |
574 | p9_idpool_put(fid->fid, clnt->fidpool); | 651 | p9_idpool_put(fid->fid, clnt->fidpool); |
575 | spin_lock(&clnt->lock); | 652 | spin_lock(&clnt->lock); |
@@ -578,49 +655,46 @@ static void p9_fid_destroy(struct p9_fid *fid) | |||
578 | kfree(fid); | 655 | kfree(fid); |
579 | } | 656 | } |
580 | 657 | ||
581 | static int p9_client_version(struct p9_client *clnt) | 658 | int p9_client_version(struct p9_client *c) |
582 | { | 659 | { |
583 | int err = 0; | 660 | int err = 0; |
584 | struct p9_fcall *tc, *rc; | 661 | struct p9_req_t *req; |
585 | struct p9_str *version; | 662 | char *version; |
663 | int msize; | ||
586 | 664 | ||
587 | P9_DPRINTK(P9_DEBUG_9P, "%p\n", clnt); | 665 | P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", |
588 | err = 0; | 666 | c->msize, c->dotu); |
589 | tc = NULL; | 667 | req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, |
590 | rc = NULL; | 668 | c->dotu ? "9P2000.u" : "9P2000"); |
591 | 669 | if (IS_ERR(req)) | |
592 | tc = p9_create_tversion(clnt->msize, | 670 | return PTR_ERR(req); |
593 | clnt->dotu ? "9P2000.u" : "9P2000"); | ||
594 | if (IS_ERR(tc)) { | ||
595 | err = PTR_ERR(tc); | ||
596 | tc = NULL; | ||
597 | goto error; | ||
598 | } | ||
599 | 671 | ||
600 | err = p9_client_rpc(clnt, tc, &rc); | 672 | err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); |
601 | if (err) | 673 | if (err) { |
674 | P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); | ||
602 | goto error; | 675 | goto error; |
676 | } | ||
603 | 677 | ||
604 | version = &rc->params.rversion.version; | 678 | P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); |
605 | if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8)) | 679 | if (!memcmp(version, "9P2000.u", 8)) |
606 | clnt->dotu = 1; | 680 | c->dotu = 1; |
607 | else if (version->len == 6 && !memcmp(version->str, "9P2000", 6)) | 681 | else if (!memcmp(version, "9P2000", 6)) |
608 | clnt->dotu = 0; | 682 | c->dotu = 0; |
609 | else { | 683 | else { |
610 | err = -EREMOTEIO; | 684 | err = -EREMOTEIO; |
611 | goto error; | 685 | goto error; |
612 | } | 686 | } |
613 | 687 | ||
614 | if (rc->params.rversion.msize < clnt->msize) | 688 | if (msize < c->msize) |
615 | clnt->msize = rc->params.rversion.msize; | 689 | c->msize = msize; |
616 | 690 | ||
617 | error: | 691 | error: |
618 | kfree(tc); | 692 | kfree(version); |
619 | kfree(rc); | 693 | p9_free_req(c, req); |
620 | 694 | ||
621 | return err; | 695 | return err; |
622 | } | 696 | } |
623 | EXPORT_SYMBOL(p9_client_auth); | 697 | EXPORT_SYMBOL(p9_client_version); |
624 | 698 | ||
625 | struct p9_client *p9_client_create(const char *dev_name, char *options) | 699 | struct p9_client *p9_client_create(const char *dev_name, char *options) |
626 | { | 700 | { |
@@ -656,7 +730,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) | |||
656 | goto error; | 730 | goto error; |
657 | } | 731 | } |
658 | 732 | ||
659 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n", | 733 | P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n", |
660 | clnt, clnt->trans_mod, clnt->msize, clnt->dotu); | 734 | clnt, clnt->trans_mod, clnt->msize, clnt->dotu); |
661 | 735 | ||
662 | err = clnt->trans_mod->create(clnt, dev_name, options); | 736 | err = clnt->trans_mod->create(clnt, dev_name, options); |
@@ -682,7 +756,7 @@ void p9_client_destroy(struct p9_client *clnt) | |||
682 | { | 756 | { |
683 | struct p9_fid *fid, *fidptr; | 757 | struct p9_fid *fid, *fidptr; |
684 | 758 | ||
685 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); | 759 | P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt); |
686 | 760 | ||
687 | if (clnt->trans_mod) | 761 | if (clnt->trans_mod) |
688 | clnt->trans_mod->close(clnt); | 762 | clnt->trans_mod->close(clnt); |
@@ -712,14 +786,13 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | |||
712 | char *uname, u32 n_uname, char *aname) | 786 | char *uname, u32 n_uname, char *aname) |
713 | { | 787 | { |
714 | int err; | 788 | int err; |
715 | struct p9_fcall *tc, *rc; | 789 | struct p9_req_t *req; |
716 | struct p9_fid *fid; | 790 | struct p9_fid *fid; |
791 | struct p9_qid qid; | ||
717 | 792 | ||
718 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n", | 793 | P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n", |
719 | clnt, afid?afid->fid:-1, uname, aname); | 794 | afid ? afid->fid : -1, uname, aname); |
720 | err = 0; | 795 | err = 0; |
721 | tc = NULL; | ||
722 | rc = NULL; | ||
723 | 796 | ||
724 | fid = p9_fid_create(clnt); | 797 | fid = p9_fid_create(clnt); |
725 | if (IS_ERR(fid)) { | 798 | if (IS_ERR(fid)) { |
@@ -728,73 +801,75 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | |||
728 | goto error; | 801 | goto error; |
729 | } | 802 | } |
730 | 803 | ||
731 | tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname, | 804 | req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid, |
732 | n_uname, clnt->dotu); | 805 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); |
733 | if (IS_ERR(tc)) { | 806 | if (IS_ERR(req)) { |
734 | err = PTR_ERR(tc); | 807 | err = PTR_ERR(req); |
735 | tc = NULL; | ||
736 | goto error; | 808 | goto error; |
737 | } | 809 | } |
738 | 810 | ||
739 | err = p9_client_rpc(clnt, tc, &rc); | 811 | err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); |
740 | if (err) | 812 | if (err) { |
813 | p9_free_req(clnt, req); | ||
741 | goto error; | 814 | goto error; |
815 | } | ||
742 | 816 | ||
743 | memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid)); | 817 | P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n", |
744 | kfree(tc); | 818 | qid.type, qid.path, qid.version); |
745 | kfree(rc); | 819 | |
820 | memmove(&fid->qid, &qid, sizeof(struct p9_qid)); | ||
821 | |||
822 | p9_free_req(clnt, req); | ||
746 | return fid; | 823 | return fid; |
747 | 824 | ||
748 | error: | 825 | error: |
749 | kfree(tc); | ||
750 | kfree(rc); | ||
751 | if (fid) | 826 | if (fid) |
752 | p9_fid_destroy(fid); | 827 | p9_fid_destroy(fid); |
753 | return ERR_PTR(err); | 828 | return ERR_PTR(err); |
754 | } | 829 | } |
755 | EXPORT_SYMBOL(p9_client_attach); | 830 | EXPORT_SYMBOL(p9_client_attach); |
756 | 831 | ||
757 | struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, | 832 | struct p9_fid * |
758 | u32 n_uname, char *aname) | 833 | p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname) |
759 | { | 834 | { |
760 | int err; | 835 | int err; |
761 | struct p9_fcall *tc, *rc; | 836 | struct p9_req_t *req; |
762 | struct p9_fid *fid; | 837 | struct p9_qid qid; |
838 | struct p9_fid *afid; | ||
763 | 839 | ||
764 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname, | 840 | P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname); |
765 | aname); | ||
766 | err = 0; | 841 | err = 0; |
767 | tc = NULL; | ||
768 | rc = NULL; | ||
769 | 842 | ||
770 | fid = p9_fid_create(clnt); | 843 | afid = p9_fid_create(clnt); |
771 | if (IS_ERR(fid)) { | 844 | if (IS_ERR(afid)) { |
772 | err = PTR_ERR(fid); | 845 | err = PTR_ERR(afid); |
773 | fid = NULL; | 846 | afid = NULL; |
774 | goto error; | 847 | goto error; |
775 | } | 848 | } |
776 | 849 | ||
777 | tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu); | 850 | req = p9_client_rpc(clnt, P9_TAUTH, "dss?d", |
778 | if (IS_ERR(tc)) { | 851 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); |
779 | err = PTR_ERR(tc); | 852 | if (IS_ERR(req)) { |
780 | tc = NULL; | 853 | err = PTR_ERR(req); |
781 | goto error; | 854 | goto error; |
782 | } | 855 | } |
783 | 856 | ||
784 | err = p9_client_rpc(clnt, tc, &rc); | 857 | err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); |
785 | if (err) | 858 | if (err) { |
859 | p9_free_req(clnt, req); | ||
786 | goto error; | 860 | goto error; |
861 | } | ||
787 | 862 | ||
788 | memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid)); | 863 | P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n", |
789 | kfree(tc); | 864 | qid.type, qid.path, qid.version); |
790 | kfree(rc); | 865 | |
791 | return fid; | 866 | memmove(&afid->qid, &qid, sizeof(struct p9_qid)); |
867 | p9_free_req(clnt, req); | ||
868 | return afid; | ||
792 | 869 | ||
793 | error: | 870 | error: |
794 | kfree(tc); | 871 | if (afid) |
795 | kfree(rc); | 872 | p9_fid_destroy(afid); |
796 | if (fid) | ||
797 | p9_fid_destroy(fid); | ||
798 | return ERR_PTR(err); | 873 | return ERR_PTR(err); |
799 | } | 874 | } |
800 | EXPORT_SYMBOL(p9_client_auth); | 875 | EXPORT_SYMBOL(p9_client_auth); |
@@ -803,15 +878,13 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, | |||
803 | int clone) | 878 | int clone) |
804 | { | 879 | { |
805 | int err; | 880 | int err; |
806 | struct p9_fcall *tc, *rc; | ||
807 | struct p9_client *clnt; | 881 | struct p9_client *clnt; |
808 | struct p9_fid *fid; | 882 | struct p9_fid *fid; |
883 | struct p9_qid *wqids; | ||
884 | struct p9_req_t *req; | ||
885 | int16_t nwqids, count; | ||
809 | 886 | ||
810 | P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n", | ||
811 | oldfid->fid, nwname, wnames?wnames[0]:NULL); | ||
812 | err = 0; | 887 | err = 0; |
813 | tc = NULL; | ||
814 | rc = NULL; | ||
815 | clnt = oldfid->clnt; | 888 | clnt = oldfid->clnt; |
816 | if (clone) { | 889 | if (clone) { |
817 | fid = p9_fid_create(clnt); | 890 | fid = p9_fid_create(clnt); |
@@ -825,53 +898,46 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, | |||
825 | } else | 898 | } else |
826 | fid = oldfid; | 899 | fid = oldfid; |
827 | 900 | ||
828 | tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames); | 901 | |
829 | if (IS_ERR(tc)) { | 902 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", |
830 | err = PTR_ERR(tc); | 903 | oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); |
831 | tc = NULL; | 904 | |
905 | req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, | ||
906 | nwname, wnames); | ||
907 | if (IS_ERR(req)) { | ||
908 | err = PTR_ERR(req); | ||
832 | goto error; | 909 | goto error; |
833 | } | 910 | } |
834 | 911 | ||
835 | err = p9_client_rpc(clnt, tc, &rc); | 912 | err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); |
836 | if (err) { | 913 | p9_free_req(clnt, req); |
837 | if (rc && rc->id == P9_RWALK) | 914 | if (err) |
838 | goto clunk_fid; | 915 | goto clunk_fid; |
839 | else | ||
840 | goto error; | ||
841 | } | ||
842 | 916 | ||
843 | if (rc->params.rwalk.nwqid != nwname) { | 917 | P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids); |
918 | |||
919 | if (nwqids != nwname) { | ||
844 | err = -ENOENT; | 920 | err = -ENOENT; |
845 | goto clunk_fid; | 921 | goto clunk_fid; |
846 | } | 922 | } |
847 | 923 | ||
924 | for (count = 0; count < nwqids; count++) | ||
925 | P9_DPRINTK(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n", | ||
926 | count, wqids[count].type, wqids[count].path, | ||
927 | wqids[count].version); | ||
928 | |||
848 | if (nwname) | 929 | if (nwname) |
849 | memmove(&fid->qid, | 930 | memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid)); |
850 | &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1], | ||
851 | sizeof(struct p9_qid)); | ||
852 | else | 931 | else |
853 | fid->qid = oldfid->qid; | 932 | fid->qid = oldfid->qid; |
854 | 933 | ||
855 | kfree(tc); | ||
856 | kfree(rc); | ||
857 | return fid; | 934 | return fid; |
858 | 935 | ||
859 | clunk_fid: | 936 | clunk_fid: |
860 | kfree(tc); | 937 | p9_client_clunk(fid); |
861 | kfree(rc); | 938 | fid = NULL; |
862 | rc = NULL; | ||
863 | tc = p9_create_tclunk(fid->fid); | ||
864 | if (IS_ERR(tc)) { | ||
865 | err = PTR_ERR(tc); | ||
866 | tc = NULL; | ||
867 | goto error; | ||
868 | } | ||
869 | |||
870 | p9_client_rpc(clnt, tc, &rc); | ||
871 | 939 | ||
872 | error: | 940 | error: |
873 | kfree(tc); | ||
874 | kfree(rc); | ||
875 | if (fid && (fid != oldfid)) | 941 | if (fid && (fid != oldfid)) |
876 | p9_fid_destroy(fid); | 942 | p9_fid_destroy(fid); |
877 | 943 | ||
@@ -882,35 +948,36 @@ EXPORT_SYMBOL(p9_client_walk); | |||
882 | int p9_client_open(struct p9_fid *fid, int mode) | 948 | int p9_client_open(struct p9_fid *fid, int mode) |
883 | { | 949 | { |
884 | int err; | 950 | int err; |
885 | struct p9_fcall *tc, *rc; | ||
886 | struct p9_client *clnt; | 951 | struct p9_client *clnt; |
952 | struct p9_req_t *req; | ||
953 | struct p9_qid qid; | ||
954 | int iounit; | ||
887 | 955 | ||
888 | P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode); | 956 | P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode); |
889 | err = 0; | 957 | err = 0; |
890 | tc = NULL; | ||
891 | rc = NULL; | ||
892 | clnt = fid->clnt; | 958 | clnt = fid->clnt; |
893 | 959 | ||
894 | if (fid->mode != -1) | 960 | if (fid->mode != -1) |
895 | return -EINVAL; | 961 | return -EINVAL; |
896 | 962 | ||
897 | tc = p9_create_topen(fid->fid, mode); | 963 | req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); |
898 | if (IS_ERR(tc)) { | 964 | if (IS_ERR(req)) { |
899 | err = PTR_ERR(tc); | 965 | err = PTR_ERR(req); |
900 | tc = NULL; | 966 | goto error; |
901 | goto done; | ||
902 | } | 967 | } |
903 | 968 | ||
904 | err = p9_client_rpc(clnt, tc, &rc); | 969 | err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); |
970 | p9_free_req(clnt, req); | ||
905 | if (err) | 971 | if (err) |
906 | goto done; | 972 | goto error; |
973 | |||
974 | P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n", | ||
975 | qid.type, qid.path, qid.version, iounit); | ||
907 | 976 | ||
908 | fid->mode = mode; | 977 | fid->mode = mode; |
909 | fid->iounit = rc->params.ropen.iounit; | 978 | fid->iounit = iounit; |
910 | 979 | ||
911 | done: | 980 | error: |
912 | kfree(tc); | ||
913 | kfree(rc); | ||
914 | return err; | 981 | return err; |
915 | } | 982 | } |
916 | EXPORT_SYMBOL(p9_client_open); | 983 | EXPORT_SYMBOL(p9_client_open); |
@@ -919,37 +986,38 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, | |||
919 | char *extension) | 986 | char *extension) |
920 | { | 987 | { |
921 | int err; | 988 | int err; |
922 | struct p9_fcall *tc, *rc; | ||
923 | struct p9_client *clnt; | 989 | struct p9_client *clnt; |
990 | struct p9_req_t *req; | ||
991 | struct p9_qid qid; | ||
992 | int iounit; | ||
924 | 993 | ||
925 | P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid, | 994 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n", |
926 | name, perm, mode); | 995 | fid->fid, name, perm, mode); |
927 | err = 0; | 996 | err = 0; |
928 | tc = NULL; | ||
929 | rc = NULL; | ||
930 | clnt = fid->clnt; | 997 | clnt = fid->clnt; |
931 | 998 | ||
932 | if (fid->mode != -1) | 999 | if (fid->mode != -1) |
933 | return -EINVAL; | 1000 | return -EINVAL; |
934 | 1001 | ||
935 | tc = p9_create_tcreate(fid->fid, name, perm, mode, extension, | 1002 | req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm, |
936 | clnt->dotu); | 1003 | mode, extension); |
937 | if (IS_ERR(tc)) { | 1004 | if (IS_ERR(req)) { |
938 | err = PTR_ERR(tc); | 1005 | err = PTR_ERR(req); |
939 | tc = NULL; | 1006 | goto error; |
940 | goto done; | ||
941 | } | 1007 | } |
942 | 1008 | ||
943 | err = p9_client_rpc(clnt, tc, &rc); | 1009 | err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); |
1010 | p9_free_req(clnt, req); | ||
944 | if (err) | 1011 | if (err) |
945 | goto done; | 1012 | goto error; |
1013 | |||
1014 | P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n", | ||
1015 | qid.type, qid.path, qid.version, iounit); | ||
946 | 1016 | ||
947 | fid->mode = mode; | 1017 | fid->mode = mode; |
948 | fid->iounit = rc->params.ropen.iounit; | 1018 | fid->iounit = iounit; |
949 | 1019 | ||
950 | done: | 1020 | error: |
951 | kfree(tc); | ||
952 | kfree(rc); | ||
953 | return err; | 1021 | return err; |
954 | } | 1022 | } |
955 | EXPORT_SYMBOL(p9_client_fcreate); | 1023 | EXPORT_SYMBOL(p9_client_fcreate); |
@@ -957,31 +1025,25 @@ EXPORT_SYMBOL(p9_client_fcreate); | |||
957 | int p9_client_clunk(struct p9_fid *fid) | 1025 | int p9_client_clunk(struct p9_fid *fid) |
958 | { | 1026 | { |
959 | int err; | 1027 | int err; |
960 | struct p9_fcall *tc, *rc; | ||
961 | struct p9_client *clnt; | 1028 | struct p9_client *clnt; |
1029 | struct p9_req_t *req; | ||
962 | 1030 | ||
963 | P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); | 1031 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); |
964 | err = 0; | 1032 | err = 0; |
965 | tc = NULL; | ||
966 | rc = NULL; | ||
967 | clnt = fid->clnt; | 1033 | clnt = fid->clnt; |
968 | 1034 | ||
969 | tc = p9_create_tclunk(fid->fid); | 1035 | req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid); |
970 | if (IS_ERR(tc)) { | 1036 | if (IS_ERR(req)) { |
971 | err = PTR_ERR(tc); | 1037 | err = PTR_ERR(req); |
972 | tc = NULL; | 1038 | goto error; |
973 | goto done; | ||
974 | } | 1039 | } |
975 | 1040 | ||
976 | err = p9_client_rpc(clnt, tc, &rc); | 1041 | P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); |
977 | if (err) | ||
978 | goto done; | ||
979 | 1042 | ||
1043 | p9_free_req(clnt, req); | ||
980 | p9_fid_destroy(fid); | 1044 | p9_fid_destroy(fid); |
981 | 1045 | ||
982 | done: | 1046 | error: |
983 | kfree(tc); | ||
984 | kfree(rc); | ||
985 | return err; | 1047 | return err; |
986 | } | 1048 | } |
987 | EXPORT_SYMBOL(p9_client_clunk); | 1049 | EXPORT_SYMBOL(p9_client_clunk); |
@@ -989,31 +1051,25 @@ EXPORT_SYMBOL(p9_client_clunk); | |||
989 | int p9_client_remove(struct p9_fid *fid) | 1051 | int p9_client_remove(struct p9_fid *fid) |
990 | { | 1052 | { |
991 | int err; | 1053 | int err; |
992 | struct p9_fcall *tc, *rc; | ||
993 | struct p9_client *clnt; | 1054 | struct p9_client *clnt; |
1055 | struct p9_req_t *req; | ||
994 | 1056 | ||
995 | P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); | 1057 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid); |
996 | err = 0; | 1058 | err = 0; |
997 | tc = NULL; | ||
998 | rc = NULL; | ||
999 | clnt = fid->clnt; | 1059 | clnt = fid->clnt; |
1000 | 1060 | ||
1001 | tc = p9_create_tremove(fid->fid); | 1061 | req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid); |
1002 | if (IS_ERR(tc)) { | 1062 | if (IS_ERR(req)) { |
1003 | err = PTR_ERR(tc); | 1063 | err = PTR_ERR(req); |
1004 | tc = NULL; | 1064 | goto error; |
1005 | goto done; | ||
1006 | } | 1065 | } |
1007 | 1066 | ||
1008 | err = p9_client_rpc(clnt, tc, &rc); | 1067 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); |
1009 | if (err) | ||
1010 | goto done; | ||
1011 | 1068 | ||
1069 | p9_free_req(clnt, req); | ||
1012 | p9_fid_destroy(fid); | 1070 | p9_fid_destroy(fid); |
1013 | 1071 | ||
1014 | done: | 1072 | error: |
1015 | kfree(tc); | ||
1016 | kfree(rc); | ||
1017 | return err; | 1073 | return err; |
1018 | } | 1074 | } |
1019 | EXPORT_SYMBOL(p9_client_remove); | 1075 | EXPORT_SYMBOL(p9_client_remove); |
@@ -1022,15 +1078,14 @@ int | |||
1022 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | 1078 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, |
1023 | u32 count) | 1079 | u32 count) |
1024 | { | 1080 | { |
1025 | int err, n, rsize, total; | 1081 | int err, rsize, total; |
1026 | struct p9_fcall *tc, *rc; | ||
1027 | struct p9_client *clnt; | 1082 | struct p9_client *clnt; |
1083 | struct p9_req_t *req; | ||
1084 | char *dataptr; | ||
1028 | 1085 | ||
1029 | P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid, | 1086 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid, |
1030 | (long long unsigned) offset, count); | 1087 | (long long unsigned) offset, count); |
1031 | err = 0; | 1088 | err = 0; |
1032 | tc = NULL; | ||
1033 | rc = NULL; | ||
1034 | clnt = fid->clnt; | 1089 | clnt = fid->clnt; |
1035 | total = 0; | 1090 | total = 0; |
1036 | 1091 | ||
@@ -1038,53 +1093,40 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1038 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | 1093 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) |
1039 | rsize = clnt->msize - P9_IOHDRSZ; | 1094 | rsize = clnt->msize - P9_IOHDRSZ; |
1040 | 1095 | ||
1041 | do { | 1096 | if (count < rsize) |
1042 | if (count < rsize) | 1097 | rsize = count; |
1043 | rsize = count; | ||
1044 | 1098 | ||
1045 | tc = p9_create_tread(fid->fid, offset, rsize); | 1099 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); |
1046 | if (IS_ERR(tc)) { | 1100 | if (IS_ERR(req)) { |
1047 | err = PTR_ERR(tc); | 1101 | err = PTR_ERR(req); |
1048 | tc = NULL; | 1102 | goto error; |
1049 | goto error; | 1103 | } |
1050 | } | ||
1051 | 1104 | ||
1052 | err = p9_client_rpc(clnt, tc, &rc); | 1105 | err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); |
1053 | if (err) | 1106 | if (err) |
1054 | goto error; | 1107 | goto free_and_error; |
1055 | 1108 | ||
1056 | n = rc->params.rread.count; | 1109 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
1057 | if (n > count) | ||
1058 | n = count; | ||
1059 | 1110 | ||
1060 | if (data) { | 1111 | if (data) { |
1061 | memmove(data, rc->params.rread.data, n); | 1112 | memmove(data, dataptr, count); |
1062 | data += n; | 1113 | data += count; |
1063 | } | 1114 | } |
1064 | 1115 | ||
1065 | if (udata) { | 1116 | if (udata) { |
1066 | err = copy_to_user(udata, rc->params.rread.data, n); | 1117 | err = copy_to_user(udata, dataptr, count); |
1067 | if (err) { | 1118 | if (err) { |
1068 | err = -EFAULT; | 1119 | err = -EFAULT; |
1069 | goto error; | 1120 | goto free_and_error; |
1070 | } | ||
1071 | udata += n; | ||
1072 | } | 1121 | } |
1122 | } | ||
1073 | 1123 | ||
1074 | count -= n; | 1124 | p9_free_req(clnt, req); |
1075 | offset += n; | 1125 | return count; |
1076 | total += n; | ||
1077 | kfree(tc); | ||
1078 | tc = NULL; | ||
1079 | kfree(rc); | ||
1080 | rc = NULL; | ||
1081 | } while (count > 0 && n == rsize); | ||
1082 | |||
1083 | return total; | ||
1084 | 1126 | ||
1127 | free_and_error: | ||
1128 | p9_free_req(clnt, req); | ||
1085 | error: | 1129 | error: |
1086 | kfree(tc); | ||
1087 | kfree(rc); | ||
1088 | return err; | 1130 | return err; |
1089 | } | 1131 | } |
1090 | EXPORT_SYMBOL(p9_client_read); | 1132 | EXPORT_SYMBOL(p9_client_read); |
@@ -1093,15 +1135,13 @@ int | |||
1093 | p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | 1135 | p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, |
1094 | u64 offset, u32 count) | 1136 | u64 offset, u32 count) |
1095 | { | 1137 | { |
1096 | int err, n, rsize, total; | 1138 | int err, rsize, total; |
1097 | struct p9_fcall *tc, *rc; | ||
1098 | struct p9_client *clnt; | 1139 | struct p9_client *clnt; |
1140 | struct p9_req_t *req; | ||
1099 | 1141 | ||
1100 | P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, | 1142 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", |
1101 | (long long unsigned) offset, count); | 1143 | fid->fid, (long long unsigned) offset, count); |
1102 | err = 0; | 1144 | err = 0; |
1103 | tc = NULL; | ||
1104 | rc = NULL; | ||
1105 | clnt = fid->clnt; | 1145 | clnt = fid->clnt; |
1106 | total = 0; | 1146 | total = 0; |
1107 | 1147 | ||
@@ -1109,129 +1149,70 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
1109 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | 1149 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) |
1110 | rsize = clnt->msize - P9_IOHDRSZ; | 1150 | rsize = clnt->msize - P9_IOHDRSZ; |
1111 | 1151 | ||
1112 | do { | 1152 | if (count < rsize) |
1113 | if (count < rsize) | 1153 | rsize = count; |
1114 | rsize = count; | 1154 | if (data) |
1115 | 1155 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, | |
1116 | if (data) | 1156 | rsize, data); |
1117 | tc = p9_create_twrite(fid->fid, offset, rsize, data); | 1157 | else |
1118 | else | 1158 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, |
1119 | tc = p9_create_twrite_u(fid->fid, offset, rsize, udata); | 1159 | rsize, udata); |
1120 | if (IS_ERR(tc)) { | 1160 | if (IS_ERR(req)) { |
1121 | err = PTR_ERR(tc); | 1161 | err = PTR_ERR(req); |
1122 | tc = NULL; | 1162 | goto error; |
1123 | goto error; | 1163 | } |
1124 | } | ||
1125 | |||
1126 | err = p9_client_rpc(clnt, tc, &rc); | ||
1127 | if (err) | ||
1128 | goto error; | ||
1129 | |||
1130 | n = rc->params.rread.count; | ||
1131 | count -= n; | ||
1132 | |||
1133 | if (data) | ||
1134 | data += n; | ||
1135 | else | ||
1136 | udata += n; | ||
1137 | 1164 | ||
1138 | offset += n; | 1165 | err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); |
1139 | total += n; | 1166 | if (err) |
1140 | kfree(tc); | 1167 | goto free_and_error; |
1141 | tc = NULL; | 1168 | P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); |
1142 | kfree(rc); | ||
1143 | rc = NULL; | ||
1144 | } while (count > 0); | ||
1145 | 1169 | ||
1146 | return total; | 1170 | p9_free_req(clnt, req); |
1171 | return count; | ||
1147 | 1172 | ||
1173 | free_and_error: | ||
1174 | p9_free_req(clnt, req); | ||
1148 | error: | 1175 | error: |
1149 | kfree(tc); | ||
1150 | kfree(rc); | ||
1151 | return err; | 1176 | return err; |
1152 | } | 1177 | } |
1153 | EXPORT_SYMBOL(p9_client_write); | 1178 | EXPORT_SYMBOL(p9_client_write); |
1154 | 1179 | ||
1155 | static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu) | 1180 | struct p9_wstat *p9_client_stat(struct p9_fid *fid) |
1156 | { | 1181 | { |
1157 | int n; | 1182 | int err; |
1158 | char *p; | 1183 | struct p9_client *clnt; |
1159 | struct p9_stat *ret; | 1184 | struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL); |
1160 | 1185 | struct p9_req_t *req; | |
1161 | n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len + | 1186 | u16 ignored; |
1162 | st->muid.len; | ||
1163 | 1187 | ||
1164 | if (dotu) | 1188 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid); |
1165 | n += st->extension.len; | ||
1166 | 1189 | ||
1167 | ret = kmalloc(n, GFP_KERNEL); | ||
1168 | if (!ret) | 1190 | if (!ret) |
1169 | return ERR_PTR(-ENOMEM); | 1191 | return ERR_PTR(-ENOMEM); |
1170 | 1192 | ||
1171 | memmove(ret, st, sizeof(struct p9_stat)); | ||
1172 | p = ((char *) ret) + sizeof(struct p9_stat); | ||
1173 | memmove(p, st->name.str, st->name.len); | ||
1174 | ret->name.str = p; | ||
1175 | p += st->name.len; | ||
1176 | memmove(p, st->uid.str, st->uid.len); | ||
1177 | ret->uid.str = p; | ||
1178 | p += st->uid.len; | ||
1179 | memmove(p, st->gid.str, st->gid.len); | ||
1180 | ret->gid.str = p; | ||
1181 | p += st->gid.len; | ||
1182 | memmove(p, st->muid.str, st->muid.len); | ||
1183 | ret->muid.str = p; | ||
1184 | p += st->muid.len; | ||
1185 | |||
1186 | if (dotu) { | ||
1187 | memmove(p, st->extension.str, st->extension.len); | ||
1188 | ret->extension.str = p; | ||
1189 | p += st->extension.len; | ||
1190 | } | ||
1191 | |||
1192 | return ret; | ||
1193 | } | ||
1194 | |||
1195 | struct p9_stat *p9_client_stat(struct p9_fid *fid) | ||
1196 | { | ||
1197 | int err; | ||
1198 | struct p9_fcall *tc, *rc; | ||
1199 | struct p9_client *clnt; | ||
1200 | struct p9_stat *ret; | ||
1201 | |||
1202 | P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); | ||
1203 | err = 0; | 1193 | err = 0; |
1204 | tc = NULL; | ||
1205 | rc = NULL; | ||
1206 | ret = NULL; | ||
1207 | clnt = fid->clnt; | 1194 | clnt = fid->clnt; |
1208 | 1195 | ||
1209 | tc = p9_create_tstat(fid->fid); | 1196 | req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid); |
1210 | if (IS_ERR(tc)) { | 1197 | if (IS_ERR(req)) { |
1211 | err = PTR_ERR(tc); | 1198 | err = PTR_ERR(req); |
1212 | tc = NULL; | ||
1213 | goto error; | 1199 | goto error; |
1214 | } | 1200 | } |
1215 | 1201 | ||
1216 | err = p9_client_rpc(clnt, tc, &rc); | 1202 | err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); |
1203 | p9_free_req(clnt, req); | ||
1217 | if (err) | 1204 | if (err) |
1218 | goto error; | 1205 | goto error; |
1219 | 1206 | ||
1220 | ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu); | 1207 | P9_DPRINTK(P9_DEBUG_9P, |
1221 | if (IS_ERR(ret)) { | 1208 | "<<< RSTAT sz=%x type=%x dev=%x qid=%2.2x %4.4x %8.8llx" |
1222 | err = PTR_ERR(ret); | 1209 | " mode=%8.8x uid=%d gid=%d size=%lld %s\n", |
1223 | ret = NULL; | 1210 | ret->size, ret->type, ret->dev, ret->qid.type, |
1224 | goto error; | 1211 | ret->qid.version, ret->qid.path, ret->mode, |
1225 | } | 1212 | ret->n_uid, ret->n_gid, ret->length, ret->name); |
1226 | 1213 | ||
1227 | kfree(tc); | ||
1228 | kfree(rc); | ||
1229 | return ret; | 1214 | return ret; |
1230 | |||
1231 | error: | 1215 | error: |
1232 | kfree(tc); | ||
1233 | kfree(rc); | ||
1234 | kfree(ret); | ||
1235 | return ERR_PTR(err); | 1216 | return ERR_PTR(err); |
1236 | } | 1217 | } |
1237 | EXPORT_SYMBOL(p9_client_stat); | 1218 | EXPORT_SYMBOL(p9_client_stat); |
@@ -1239,27 +1220,23 @@ EXPORT_SYMBOL(p9_client_stat); | |||
1239 | int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) | 1220 | int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) |
1240 | { | 1221 | { |
1241 | int err; | 1222 | int err; |
1242 | struct p9_fcall *tc, *rc; | 1223 | struct p9_req_t *req; |
1243 | struct p9_client *clnt; | 1224 | struct p9_client *clnt; |
1244 | 1225 | ||
1245 | P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); | 1226 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); |
1246 | err = 0; | 1227 | err = 0; |
1247 | tc = NULL; | ||
1248 | rc = NULL; | ||
1249 | clnt = fid->clnt; | 1228 | clnt = fid->clnt; |
1250 | 1229 | ||
1251 | tc = p9_create_twstat(fid->fid, wst, clnt->dotu); | 1230 | req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, 0, wst); |
1252 | if (IS_ERR(tc)) { | 1231 | if (IS_ERR(req)) { |
1253 | err = PTR_ERR(tc); | 1232 | err = PTR_ERR(req); |
1254 | tc = NULL; | 1233 | goto error; |
1255 | goto done; | ||
1256 | } | 1234 | } |
1257 | 1235 | ||
1258 | err = p9_client_rpc(clnt, tc, &rc); | 1236 | P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid); |
1259 | 1237 | ||
1260 | done: | 1238 | p9_free_req(clnt, req); |
1261 | kfree(tc); | 1239 | error: |
1262 | kfree(rc); | ||
1263 | return err; | 1240 | return err; |
1264 | } | 1241 | } |
1265 | EXPORT_SYMBOL(p9_client_wstat); | 1242 | EXPORT_SYMBOL(p9_client_wstat); |