aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew R. Ochs <mrochs@linux.vnet.ibm.com>2016-08-09 19:39:42 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2016-08-18 22:41:36 -0400
commit888baf069f49529f33c0b1dfb0fc4811dc0ca1d2 (patch)
tree6adddf35f84cb2a08756eeef7a0b8d6fb0ab56ed
parent44ef38f9a2af8644c24ace6cbe1132dc70174c39 (diff)
scsi: cxlflash: Add kref to context
Currently, context user references are tracked via the list of LUNs that have attached to the context. While convenient, this is not intuitive without a deep study of the code and is inconsistent with the existing reference tracking patterns within the kernel. This design choice can lead to future bug injection. To improve code comprehension and better protect against future bugs, add explicit reference counting to contexts and migrate the context removal code to the kref release handler. Inspired-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com> Acked-by: Manoj N. Kumar <manoj@linux.vnet.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/cxlflash/superpipe.c87
-rw-r--r--drivers/scsi/cxlflash/superpipe.h1
2 files changed, 53 insertions, 35 deletions
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index 640c3a2641ef..be7522ae02a4 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -808,11 +808,56 @@ static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg,
808 ctxi->file = file; 808 ctxi->file = file;
809 ctxi->initialized = true; 809 ctxi->initialized = true;
810 mutex_init(&ctxi->mutex); 810 mutex_init(&ctxi->mutex);
811 kref_init(&ctxi->kref);
811 INIT_LIST_HEAD(&ctxi->luns); 812 INIT_LIST_HEAD(&ctxi->luns);
812 INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ 813 INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */
813} 814}
814 815
815/** 816/**
817 * remove_context() - context kref release handler
818 * @kref: Kernel reference associated with context to be removed.
819 *
820 * When a context no longer has any references it can safely be removed
821 * from global access and destroyed. Note that it is assumed the thread
822 * relinquishing access to the context holds its mutex.
823 */
824static void remove_context(struct kref *kref)
825{
826 struct ctx_info *ctxi = container_of(kref, struct ctx_info, kref);
827 struct cxlflash_cfg *cfg = ctxi->cfg;
828 int lfd;
829 u64 ctxid = DECODE_CTXID(ctxi->ctxid);
830
831 /* Remove context from table/error list */
832 WARN_ON(!mutex_is_locked(&ctxi->mutex));
833 ctxi->unavail = true;
834 mutex_unlock(&ctxi->mutex);
835 mutex_lock(&cfg->ctx_tbl_list_mutex);
836 mutex_lock(&ctxi->mutex);
837
838 if (!list_empty(&ctxi->list))
839 list_del(&ctxi->list);
840 cfg->ctx_tbl[ctxid] = NULL;
841 mutex_unlock(&cfg->ctx_tbl_list_mutex);
842 mutex_unlock(&ctxi->mutex);
843
844 /* Context now completely uncoupled/unreachable */
845 lfd = ctxi->lfd;
846 destroy_context(cfg, ctxi);
847
848 /*
849 * As a last step, clean up external resources when not
850 * already on an external cleanup thread, i.e.: close(adap_fd).
851 *
852 * NOTE: this will free up the context from the CXL services,
853 * allowing it to dole out the same context_id on a future
854 * (or even currently in-flight) disk_attach operation.
855 */
856 if (lfd != -1)
857 sys_close(lfd);
858}
859
860/**
816 * _cxlflash_disk_detach() - detaches a LUN from a context 861 * _cxlflash_disk_detach() - detaches a LUN from a context
817 * @sdev: SCSI device associated with LUN. 862 * @sdev: SCSI device associated with LUN.
818 * @ctxi: Context owning resources. 863 * @ctxi: Context owning resources.
@@ -837,7 +882,6 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev,
837 882
838 int i; 883 int i;
839 int rc = 0; 884 int rc = 0;
840 int lfd;
841 u64 ctxid = DECODE_CTXID(detach->context_id), 885 u64 ctxid = DECODE_CTXID(detach->context_id),
842 rctxid = detach->context_id; 886 rctxid = detach->context_id;
843 887
@@ -879,40 +923,12 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev,
879 break; 923 break;
880 } 924 }
881 925
882 /* Tear down context following last LUN cleanup */ 926 /*
883 if (list_empty(&ctxi->luns)) { 927 * Release the context reference and the sdev reference that
884 ctxi->unavail = true; 928 * bound this LUN to the context.
885 mutex_unlock(&ctxi->mutex); 929 */
886 mutex_lock(&cfg->ctx_tbl_list_mutex); 930 put_ctx = !kref_put(&ctxi->kref, remove_context);
887 mutex_lock(&ctxi->mutex);
888
889 /* Might not have been in error list so conditionally remove */
890 if (!list_empty(&ctxi->list))
891 list_del(&ctxi->list);
892 cfg->ctx_tbl[ctxid] = NULL;
893 mutex_unlock(&cfg->ctx_tbl_list_mutex);
894 mutex_unlock(&ctxi->mutex);
895
896 lfd = ctxi->lfd;
897 destroy_context(cfg, ctxi);
898 ctxi = NULL;
899 put_ctx = false;
900
901 /*
902 * As a last step, clean up external resources when not
903 * already on an external cleanup thread, i.e.: close(adap_fd).
904 *
905 * NOTE: this will free up the context from the CXL services,
906 * allowing it to dole out the same context_id on a future
907 * (or even currently in-flight) disk_attach operation.
908 */
909 if (lfd != -1)
910 sys_close(lfd);
911 }
912
913 /* Release the sdev reference that bound this LUN to the context */
914 scsi_device_put(sdev); 931 scsi_device_put(sdev);
915
916out: 932out:
917 if (put_ctx) 933 if (put_ctx)
918 put_context(ctxi); 934 put_context(ctxi);
@@ -1369,10 +1385,11 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
1369 lun_access->lli = lli; 1385 lun_access->lli = lli;
1370 lun_access->sdev = sdev; 1386 lun_access->sdev = sdev;
1371 1387
1372 /* Non-NULL context indicates reuse */ 1388 /* Non-NULL context indicates reuse (another context reference) */
1373 if (ctxi) { 1389 if (ctxi) {
1374 dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n", 1390 dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n",
1375 __func__, rctxid); 1391 __func__, rctxid);
1392 kref_get(&ctxi->kref);
1376 list_add(&lun_access->list, &ctxi->luns); 1393 list_add(&lun_access->list, &ctxi->luns);
1377 fd = ctxi->lfd; 1394 fd = ctxi->lfd;
1378 goto out_attach; 1395 goto out_attach;
diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h
index 61404f201deb..5bda8b5758d5 100644
--- a/drivers/scsi/cxlflash/superpipe.h
+++ b/drivers/scsi/cxlflash/superpipe.h
@@ -106,6 +106,7 @@ struct ctx_info {
106 bool unavail; 106 bool unavail;
107 bool err_recovery_active; 107 bool err_recovery_active;
108 struct mutex mutex; /* Context protection */ 108 struct mutex mutex; /* Context protection */
109 struct kref kref;
109 struct cxl_context *ctx; 110 struct cxl_context *ctx;
110 struct cxlflash_cfg *cfg; 111 struct cxlflash_cfg *cfg;
111 struct list_head luns; /* LUNs attached to this context */ 112 struct list_head luns; /* LUNs attached to this context */