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,10 +808,55 @@ static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg, ctxi->file = file; ctxi->initialized = true; mutex_init(&ctxi->mutex); + kref_init(&ctxi->kref); INIT_LIST_HEAD(&ctxi->luns); INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ } +/** + * remove_context() - context kref release handler + * @kref: Kernel reference associated with context to be removed. + * + * When a context no longer has any references it can safely be removed + * from global access and destroyed. Note that it is assumed the thread + * relinquishing access to the context holds its mutex. + */ +static void remove_context(struct kref *kref) +{ + struct ctx_info *ctxi = container_of(kref, struct ctx_info, kref); + struct cxlflash_cfg *cfg = ctxi->cfg; + int lfd; + u64 ctxid = DECODE_CTXID(ctxi->ctxid); + + /* Remove context from table/error list */ + WARN_ON(!mutex_is_locked(&ctxi->mutex)); + ctxi->unavail = true; + mutex_unlock(&ctxi->mutex); + mutex_lock(&cfg->ctx_tbl_list_mutex); + mutex_lock(&ctxi->mutex); + + if (!list_empty(&ctxi->list)) + list_del(&ctxi->list); + cfg->ctx_tbl[ctxid] = NULL; + mutex_unlock(&cfg->ctx_tbl_list_mutex); + mutex_unlock(&ctxi->mutex); + + /* Context now completely uncoupled/unreachable */ + lfd = ctxi->lfd; + destroy_context(cfg, ctxi); + + /* + * As a last step, clean up external resources when not + * already on an external cleanup thread, i.e.: close(adap_fd). + * + * NOTE: this will free up the context from the CXL services, + * allowing it to dole out the same context_id on a future + * (or even currently in-flight) disk_attach operation. + */ + if (lfd != -1) + sys_close(lfd); +} + /** * _cxlflash_disk_detach() - detaches a LUN from a context * @sdev: SCSI device associated with LUN. @@ -837,7 +882,6 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev, int i; int rc = 0; - int lfd; u64 ctxid = DECODE_CTXID(detach->context_id), rctxid = detach->context_id; @@ -879,40 +923,12 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev, break; } - /* Tear down context following last LUN cleanup */ - if (list_empty(&ctxi->luns)) { - ctxi->unavail = true; - mutex_unlock(&ctxi->mutex); - mutex_lock(&cfg->ctx_tbl_list_mutex); - mutex_lock(&ctxi->mutex); - - /* Might not have been in error list so conditionally remove */ - if (!list_empty(&ctxi->list)) - list_del(&ctxi->list); - cfg->ctx_tbl[ctxid] = NULL; - mutex_unlock(&cfg->ctx_tbl_list_mutex); - mutex_unlock(&ctxi->mutex); - - lfd = ctxi->lfd; - destroy_context(cfg, ctxi); - ctxi = NULL; - put_ctx = false; - - /* - * As a last step, clean up external resources when not - * already on an external cleanup thread, i.e.: close(adap_fd). - * - * NOTE: this will free up the context from the CXL services, - * allowing it to dole out the same context_id on a future - * (or even currently in-flight) disk_attach operation. - */ - if (lfd != -1) - sys_close(lfd); - } - - /* Release the sdev reference that bound this LUN to the context */ + /* + * Release the context reference and the sdev reference that + * bound this LUN to the context. + */ + put_ctx = !kref_put(&ctxi->kref, remove_context); scsi_device_put(sdev); - out: if (put_ctx) put_context(ctxi); @@ -1369,10 +1385,11 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, lun_access->lli = lli; lun_access->sdev = sdev; - /* Non-NULL context indicates reuse */ + /* Non-NULL context indicates reuse (another context reference) */ if (ctxi) { dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n", __func__, rctxid); + kref_get(&ctxi->kref); list_add(&lun_access->list, &ctxi->luns); fd = ctxi->lfd; 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 { bool unavail; bool err_recovery_active; struct mutex mutex; /* Context protection */ + struct kref kref; struct cxl_context *ctx; struct cxlflash_cfg *cfg; struct list_head luns; /* LUNs attached to this context */