aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/nvme/target/fcloop.c147
1 files changed, 125 insertions, 22 deletions
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index c5015199c031..9f8a6726df91 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -242,13 +242,22 @@ struct fcloop_lsreq {
242 int status; 242 int status;
243}; 243};
244 244
245enum {
246 INI_IO_START = 0,
247 INI_IO_ACTIVE = 1,
248 INI_IO_ABORTED = 2,
249 INI_IO_COMPLETED = 3,
250};
251
245struct fcloop_fcpreq { 252struct fcloop_fcpreq {
246 struct fcloop_tport *tport; 253 struct fcloop_tport *tport;
247 struct nvmefc_fcp_req *fcpreq; 254 struct nvmefc_fcp_req *fcpreq;
248 spinlock_t reqlock; 255 spinlock_t reqlock;
249 u16 status; 256 u16 status;
257 u32 inistate;
250 bool active; 258 bool active;
251 bool aborted; 259 bool aborted;
260 struct kref ref;
252 struct work_struct fcp_rcv_work; 261 struct work_struct fcp_rcv_work;
253 struct work_struct abort_rcv_work; 262 struct work_struct abort_rcv_work;
254 struct work_struct tio_done_work; 263 struct work_struct tio_done_work;
@@ -258,6 +267,7 @@ struct fcloop_fcpreq {
258struct fcloop_ini_fcpreq { 267struct fcloop_ini_fcpreq {
259 struct nvmefc_fcp_req *fcpreq; 268 struct nvmefc_fcp_req *fcpreq;
260 struct fcloop_fcpreq *tfcp_req; 269 struct fcloop_fcpreq *tfcp_req;
270 spinlock_t inilock;
261}; 271};
262 272
263static inline struct fcloop_lsreq * 273static inline struct fcloop_lsreq *
@@ -349,24 +359,24 @@ fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *tport,
349} 359}
350 360
351static void 361static void
352fcloop_fcp_recv_work(struct work_struct *work) 362fcloop_tfcp_req_free(struct kref *ref)
353{ 363{
354 struct fcloop_fcpreq *tfcp_req = 364 struct fcloop_fcpreq *tfcp_req =
355 container_of(work, struct fcloop_fcpreq, fcp_rcv_work); 365 container_of(ref, struct fcloop_fcpreq, ref);
356 struct nvmefc_fcp_req *fcpreq = tfcp_req->fcpreq;
357 struct fcloop_ini_fcpreq *inireq = NULL;
358 int ret = 0;
359 366
360 ret = nvmet_fc_rcv_fcp_req(tfcp_req->tport->targetport, 367 kfree(tfcp_req);
361 &tfcp_req->tgt_fcp_req, 368}
362 fcpreq->cmdaddr, fcpreq->cmdlen);
363 if (ret) {
364 inireq = fcpreq->private;
365 inireq->tfcp_req = NULL;
366 369
367 fcpreq->status = tfcp_req->status; 370static void
368 fcpreq->done(fcpreq); 371fcloop_tfcp_req_put(struct fcloop_fcpreq *tfcp_req)
369 } 372{
373 kref_put(&tfcp_req->ref, fcloop_tfcp_req_free);
374}
375
376static int
377fcloop_tfcp_req_get(struct fcloop_fcpreq *tfcp_req)
378{
379 return kref_get_unless_zero(&tfcp_req->ref);
370} 380}
371 381
372static void 382static void
@@ -377,11 +387,52 @@ fcloop_call_host_done(struct nvmefc_fcp_req *fcpreq,
377 387
378 if (fcpreq) { 388 if (fcpreq) {
379 inireq = fcpreq->private; 389 inireq = fcpreq->private;
390 spin_lock(&inireq->inilock);
380 inireq->tfcp_req = NULL; 391 inireq->tfcp_req = NULL;
392 spin_unlock(&inireq->inilock);
381 393
382 fcpreq->status = status; 394 fcpreq->status = status;
383 fcpreq->done(fcpreq); 395 fcpreq->done(fcpreq);
384 } 396 }
397
398 /* release original io reference on tgt struct */
399 fcloop_tfcp_req_put(tfcp_req);
400}
401
402static void
403fcloop_fcp_recv_work(struct work_struct *work)
404{
405 struct fcloop_fcpreq *tfcp_req =
406 container_of(work, struct fcloop_fcpreq, fcp_rcv_work);
407 struct nvmefc_fcp_req *fcpreq = tfcp_req->fcpreq;
408 int ret = 0;
409 bool aborted = false;
410
411 spin_lock(&tfcp_req->reqlock);
412 switch (tfcp_req->inistate) {
413 case INI_IO_START:
414 tfcp_req->inistate = INI_IO_ACTIVE;
415 break;
416 case INI_IO_ABORTED:
417 aborted = true;
418 break;
419 default:
420 spin_unlock(&tfcp_req->reqlock);
421 WARN_ON(1);
422 return;
423 }
424 spin_unlock(&tfcp_req->reqlock);
425
426 if (unlikely(aborted))
427 ret = -ECANCELED;
428 else
429 ret = nvmet_fc_rcv_fcp_req(tfcp_req->tport->targetport,
430 &tfcp_req->tgt_fcp_req,
431 fcpreq->cmdaddr, fcpreq->cmdlen);
432 if (ret)
433 fcloop_call_host_done(fcpreq, tfcp_req, ret);
434
435 return;
385} 436}
386 437
387static void 438static void
@@ -389,7 +440,29 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
389{ 440{
390 struct fcloop_fcpreq *tfcp_req = 441 struct fcloop_fcpreq *tfcp_req =
391 container_of(work, struct fcloop_fcpreq, abort_rcv_work); 442 container_of(work, struct fcloop_fcpreq, abort_rcv_work);
392 struct nvmefc_fcp_req *fcpreq = tfcp_req->fcpreq; 443 struct nvmefc_fcp_req *fcpreq;
444 bool completed = false;
445
446 spin_lock(&tfcp_req->reqlock);
447 fcpreq = tfcp_req->fcpreq;
448 switch (tfcp_req->inistate) {
449 case INI_IO_ABORTED:
450 break;
451 case INI_IO_COMPLETED:
452 completed = true;
453 break;
454 default:
455 spin_unlock(&tfcp_req->reqlock);
456 WARN_ON(1);
457 return;
458 }
459 spin_unlock(&tfcp_req->reqlock);
460
461 if (unlikely(completed)) {
462 /* remove reference taken in original abort downcall */
463 fcloop_tfcp_req_put(tfcp_req);
464 return;
465 }
393 466
394 if (tfcp_req->tport->targetport) 467 if (tfcp_req->tport->targetport)
395 nvmet_fc_rcv_fcp_abort(tfcp_req->tport->targetport, 468 nvmet_fc_rcv_fcp_abort(tfcp_req->tport->targetport,
@@ -400,6 +473,7 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
400 spin_unlock(&tfcp_req->reqlock); 473 spin_unlock(&tfcp_req->reqlock);
401 474
402 fcloop_call_host_done(fcpreq, tfcp_req, -ECANCELED); 475 fcloop_call_host_done(fcpreq, tfcp_req, -ECANCELED);
476 /* call_host_done releases reference for abort downcall */
403} 477}
404 478
405/* 479/*
@@ -415,12 +489,10 @@ fcloop_tgt_fcprqst_done_work(struct work_struct *work)
415 489
416 spin_lock(&tfcp_req->reqlock); 490 spin_lock(&tfcp_req->reqlock);
417 fcpreq = tfcp_req->fcpreq; 491 fcpreq = tfcp_req->fcpreq;
418 tfcp_req->fcpreq = NULL; 492 tfcp_req->inistate = INI_IO_COMPLETED;
419 spin_unlock(&tfcp_req->reqlock); 493 spin_unlock(&tfcp_req->reqlock);
420 494
421 fcloop_call_host_done(fcpreq, tfcp_req, tfcp_req->status); 495 fcloop_call_host_done(fcpreq, tfcp_req, tfcp_req->status);
422
423 kfree(tfcp_req);
424} 496}
425 497
426 498
@@ -443,12 +515,16 @@ fcloop_fcp_req(struct nvme_fc_local_port *localport,
443 515
444 inireq->fcpreq = fcpreq; 516 inireq->fcpreq = fcpreq;
445 inireq->tfcp_req = tfcp_req; 517 inireq->tfcp_req = tfcp_req;
518 spin_lock_init(&inireq->inilock);
519
446 tfcp_req->fcpreq = fcpreq; 520 tfcp_req->fcpreq = fcpreq;
447 tfcp_req->tport = rport->targetport->private; 521 tfcp_req->tport = rport->targetport->private;
522 tfcp_req->inistate = INI_IO_START;
448 spin_lock_init(&tfcp_req->reqlock); 523 spin_lock_init(&tfcp_req->reqlock);
449 INIT_WORK(&tfcp_req->fcp_rcv_work, fcloop_fcp_recv_work); 524 INIT_WORK(&tfcp_req->fcp_rcv_work, fcloop_fcp_recv_work);
450 INIT_WORK(&tfcp_req->abort_rcv_work, fcloop_fcp_abort_recv_work); 525 INIT_WORK(&tfcp_req->abort_rcv_work, fcloop_fcp_abort_recv_work);
451 INIT_WORK(&tfcp_req->tio_done_work, fcloop_tgt_fcprqst_done_work); 526 INIT_WORK(&tfcp_req->tio_done_work, fcloop_tgt_fcprqst_done_work);
527 kref_init(&tfcp_req->ref);
452 528
453 schedule_work(&tfcp_req->fcp_rcv_work); 529 schedule_work(&tfcp_req->fcp_rcv_work);
454 530
@@ -648,7 +724,14 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
648 struct nvmefc_fcp_req *fcpreq) 724 struct nvmefc_fcp_req *fcpreq)
649{ 725{
650 struct fcloop_ini_fcpreq *inireq = fcpreq->private; 726 struct fcloop_ini_fcpreq *inireq = fcpreq->private;
651 struct fcloop_fcpreq *tfcp_req = inireq->tfcp_req; 727 struct fcloop_fcpreq *tfcp_req;
728 bool abortio = true;
729
730 spin_lock(&inireq->inilock);
731 tfcp_req = inireq->tfcp_req;
732 if (tfcp_req)
733 fcloop_tfcp_req_get(tfcp_req);
734 spin_unlock(&inireq->inilock);
652 735
653 if (!tfcp_req) 736 if (!tfcp_req)
654 /* abort has already been called */ 737 /* abort has already been called */
@@ -656,11 +739,31 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
656 739
657 /* break initiator/target relationship for io */ 740 /* break initiator/target relationship for io */
658 spin_lock(&tfcp_req->reqlock); 741 spin_lock(&tfcp_req->reqlock);
659 inireq->tfcp_req = NULL; 742 switch (tfcp_req->inistate) {
660 tfcp_req->fcpreq = NULL; 743 case INI_IO_START:
744 case INI_IO_ACTIVE:
745 tfcp_req->inistate = INI_IO_ABORTED;
746 break;
747 case INI_IO_COMPLETED:
748 abortio = false;
749 break;
750 default:
751 spin_unlock(&tfcp_req->reqlock);
752 WARN_ON(1);
753 return;
754 }
661 spin_unlock(&tfcp_req->reqlock); 755 spin_unlock(&tfcp_req->reqlock);
662 756
663 WARN_ON(!schedule_work(&tfcp_req->abort_rcv_work)); 757 if (abortio)
758 /* leave the reference while the work item is scheduled */
759 WARN_ON(!schedule_work(&tfcp_req->abort_rcv_work));
760 else {
761 /*
762 * as the io has already had the done callback made,
763 * nothing more to do. So release the reference taken above
764 */
765 fcloop_tfcp_req_put(tfcp_req);
766 }
664} 767}
665 768
666static void 769static void