mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
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>
This commit is contained in:
parent
44ef38f9a2
commit
888baf069f
2 changed files with 53 additions and 35 deletions
|
@ -808,10 +808,55 @@ static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg,
|
||||||
ctxi->file = file;
|
ctxi->file = file;
|
||||||
ctxi->initialized = true;
|
ctxi->initialized = true;
|
||||||
mutex_init(&ctxi->mutex);
|
mutex_init(&ctxi->mutex);
|
||||||
|
kref_init(&ctxi->kref);
|
||||||
INIT_LIST_HEAD(&ctxi->luns);
|
INIT_LIST_HEAD(&ctxi->luns);
|
||||||
INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */
|
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
|
* _cxlflash_disk_detach() - detaches a LUN from a context
|
||||||
* @sdev: SCSI device associated with LUN.
|
* @sdev: SCSI device associated with LUN.
|
||||||
|
@ -837,7 +882,6 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev,
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int lfd;
|
|
||||||
u64 ctxid = DECODE_CTXID(detach->context_id),
|
u64 ctxid = DECODE_CTXID(detach->context_id),
|
||||||
rctxid = detach->context_id;
|
rctxid = detach->context_id;
|
||||||
|
|
||||||
|
@ -879,40 +923,12 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev,
|
||||||
break;
|
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
|
* Release the context reference and the sdev reference that
|
||||||
* already on an external cleanup thread, i.e.: close(adap_fd).
|
* bound this LUN to the context.
|
||||||
*
|
|
||||||
* 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)
|
put_ctx = !kref_put(&ctxi->kref, remove_context);
|
||||||
sys_close(lfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release the sdev reference that bound this LUN to the context */
|
|
||||||
scsi_device_put(sdev);
|
scsi_device_put(sdev);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (put_ctx)
|
if (put_ctx)
|
||||||
put_context(ctxi);
|
put_context(ctxi);
|
||||||
|
@ -1369,10 +1385,11 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
|
||||||
lun_access->lli = lli;
|
lun_access->lli = lli;
|
||||||
lun_access->sdev = sdev;
|
lun_access->sdev = sdev;
|
||||||
|
|
||||||
/* Non-NULL context indicates reuse */
|
/* Non-NULL context indicates reuse (another context reference) */
|
||||||
if (ctxi) {
|
if (ctxi) {
|
||||||
dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n",
|
dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n",
|
||||||
__func__, rctxid);
|
__func__, rctxid);
|
||||||
|
kref_get(&ctxi->kref);
|
||||||
list_add(&lun_access->list, &ctxi->luns);
|
list_add(&lun_access->list, &ctxi->luns);
|
||||||
fd = ctxi->lfd;
|
fd = ctxi->lfd;
|
||||||
goto out_attach;
|
goto out_attach;
|
||||||
|
|
|
@ -106,6 +106,7 @@ struct ctx_info {
|
||||||
bool unavail;
|
bool unavail;
|
||||||
bool err_recovery_active;
|
bool err_recovery_active;
|
||||||
struct mutex mutex; /* Context protection */
|
struct mutex mutex; /* Context protection */
|
||||||
|
struct kref kref;
|
||||||
struct cxl_context *ctx;
|
struct cxl_context *ctx;
|
||||||
struct cxlflash_cfg *cfg;
|
struct cxlflash_cfg *cfg;
|
||||||
struct list_head luns; /* LUNs attached to this context */
|
struct list_head luns; /* LUNs attached to this context */
|
||||||
|
|
Loading…
Reference in a new issue