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.
int i;
int rc = 0;
- int lfd;
u64 ctxid = DECODE_CTXID(detach->context_id),
rctxid = detach->context_id;
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);
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;