scst_copy_mgr, initial inquiry: Fix up the error handling

1. scst_cm_send_init_inquiry() gets a reference on struct scst_device, but
   doesn't put it in case of an error, so this may cause a reference leak.

2. scst_cm_init_inq_finish() shouldn't put a reference on struct
   scst_device during the retry, since we have to hold the reference as
   long as there is a pointer to struct scst_device in the priv field.
   Otherwise, the retry command will run without holding the reference.

Fixes: ec3c6b5a ("scst_copy_mgr, initial inquiry: Hold a reference on
struct scst_device")
This commit is contained in:
Gleb Chesnokov
2022-07-23 16:06:48 +03:00
parent f06a86e4aa
commit 4a02996629

View File

@@ -2341,7 +2341,7 @@ static void scst_cm_init_inq_finish(struct scst_cmd *cmd)
PRINT_CRIT_ERROR("Unable to perform initial INQUIRY for device "
"%s. Copy manager for this device will be disabled",
dev->virt_name);
goto out;
goto out_put_ref;
}
length = scst_get_buf_full(cmd, &buf, false);
@@ -2349,7 +2349,7 @@ static void scst_cm_init_inq_finish(struct scst_cmd *cmd)
if (unlikely(length <= 0)) {
if (length < 0)
PRINT_ERROR("scst_get_buf_full() failed: %d", length);
goto out;
goto out_put_ref;
}
TRACE_BUFF_FLAG(TRACE_DEBUG, "buf", buf, length);
@@ -2425,8 +2425,10 @@ next:
out_put:
scst_put_buf_full(cmd, buf);
out:
out_put_ref:
percpu_ref_put(&dev->refcnt);
out:
TRACE_EXIT();
return;
}
@@ -2434,15 +2436,17 @@ out:
static int scst_cm_send_init_inquiry(struct scst_device *dev,
unsigned int unpacked_lun, struct scst_cm_init_inq_priv *priv)
{
int res = -EINVAL;
static const uint8_t inq_cdb[6] = { INQUIRY, 1, 0x83, 0x10, 0, 0 };
__be64 lun;
struct scst_cmd *cmd;
int res = 0;
TRACE_ENTRY();
if (WARN_ON_ONCE(!dev))
if (WARN_ON_ONCE(!dev)) {
res = -EINVAL;
goto out;
}
if (priv == NULL) {
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -2473,13 +2477,13 @@ static int scst_cm_send_init_inquiry(struct scst_device *dev,
scst_cmd_init_done(cmd, SCST_CONTEXT_THREAD);
res = 0;
out:
TRACE_EXIT_RES(res);
return res;
out_free:
percpu_ref_put(&dev->refcnt);
kfree(priv);
goto out;
}