diff options
| author | Mike Christie <mchristi@redhat.com> | 2018-06-22 17:40:19 -0400 |
|---|---|---|
| committer | Martin K. Petersen <martin.petersen@oracle.com> | 2018-06-26 12:27:05 -0400 |
| commit | 3228691ffec134353cb5bf6fb4342283e0243412 (patch) | |
| tree | 46efebf9fc6b44dac7ede03eea16a49c27722cc6 /drivers/target/target_core_user.c | |
| parent | 0297e962907d98ece34188cb267d3313812b6e42 (diff) | |
scsi: tcmu: track nl commands
The next patch is going to fix the hung nl command issue so this adds a
list of outstanding nl commands that we can later abort when the daemon is
restarted.
Signed-off-by: Mike Christie <mchristi@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/target/target_core_user.c')
| -rw-r--r-- | drivers/target/target_core_user.c | 68 |
1 files changed, 39 insertions, 29 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 898a5619f2d6..73a57681e312 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c | |||
| @@ -103,9 +103,16 @@ struct tcmu_hba { | |||
| 103 | 103 | ||
| 104 | #define TCMU_CONFIG_LEN 256 | 104 | #define TCMU_CONFIG_LEN 256 |
| 105 | 105 | ||
| 106 | static DEFINE_MUTEX(tcmu_nl_cmd_mutex); | ||
| 107 | static LIST_HEAD(tcmu_nl_cmd_list); | ||
| 108 | |||
| 109 | struct tcmu_dev; | ||
| 110 | |||
| 106 | struct tcmu_nl_cmd { | 111 | struct tcmu_nl_cmd { |
| 107 | /* wake up thread waiting for reply */ | 112 | /* wake up thread waiting for reply */ |
| 108 | struct completion complete; | 113 | struct completion complete; |
| 114 | struct list_head nl_list; | ||
| 115 | struct tcmu_dev *udev; | ||
| 109 | int cmd; | 116 | int cmd; |
| 110 | int status; | 117 | int status; |
| 111 | }; | 118 | }; |
| @@ -157,7 +164,6 @@ struct tcmu_dev { | |||
| 157 | 164 | ||
| 158 | struct list_head timedout_entry; | 165 | struct list_head timedout_entry; |
| 159 | 166 | ||
| 160 | spinlock_t nl_cmd_lock; | ||
| 161 | struct tcmu_nl_cmd curr_nl_cmd; | 167 | struct tcmu_nl_cmd curr_nl_cmd; |
| 162 | /* wake up threads waiting on curr_nl_cmd */ | 168 | /* wake up threads waiting on curr_nl_cmd */ |
| 163 | wait_queue_head_t nl_cmd_wq; | 169 | wait_queue_head_t nl_cmd_wq; |
| @@ -270,11 +276,9 @@ static struct nla_policy tcmu_attr_policy[TCMU_ATTR_MAX+1] = { | |||
| 270 | 276 | ||
| 271 | static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) | 277 | static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) |
| 272 | { | 278 | { |
| 273 | struct se_device *dev; | 279 | struct tcmu_dev *udev = NULL; |
| 274 | struct tcmu_dev *udev; | ||
| 275 | struct tcmu_nl_cmd *nl_cmd; | 280 | struct tcmu_nl_cmd *nl_cmd; |
| 276 | int dev_id, rc, ret = 0; | 281 | int dev_id, rc, ret = 0; |
| 277 | bool is_removed = (completed_cmd == TCMU_CMD_REMOVED_DEVICE); | ||
| 278 | 282 | ||
| 279 | if (!info->attrs[TCMU_ATTR_CMD_STATUS] || | 283 | if (!info->attrs[TCMU_ATTR_CMD_STATUS] || |
| 280 | !info->attrs[TCMU_ATTR_DEVICE_ID]) { | 284 | !info->attrs[TCMU_ATTR_DEVICE_ID]) { |
| @@ -285,33 +289,36 @@ static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) | |||
| 285 | dev_id = nla_get_u32(info->attrs[TCMU_ATTR_DEVICE_ID]); | 289 | dev_id = nla_get_u32(info->attrs[TCMU_ATTR_DEVICE_ID]); |
| 286 | rc = nla_get_s32(info->attrs[TCMU_ATTR_CMD_STATUS]); | 290 | rc = nla_get_s32(info->attrs[TCMU_ATTR_CMD_STATUS]); |
| 287 | 291 | ||
| 288 | dev = target_find_device(dev_id, !is_removed); | 292 | mutex_lock(&tcmu_nl_cmd_mutex); |
| 289 | if (!dev) { | 293 | list_for_each_entry(nl_cmd, &tcmu_nl_cmd_list, nl_list) { |
| 290 | printk(KERN_ERR "tcmu nl cmd %u/%u completion could not find device with dev id %u.\n", | 294 | if (nl_cmd->udev->se_dev.dev_index == dev_id) { |
| 291 | completed_cmd, rc, dev_id); | 295 | udev = nl_cmd->udev; |
| 292 | return -ENODEV; | 296 | break; |
| 297 | } | ||
| 293 | } | 298 | } |
| 294 | udev = TCMU_DEV(dev); | ||
| 295 | 299 | ||
| 296 | spin_lock(&udev->nl_cmd_lock); | 300 | if (!udev) { |
| 297 | nl_cmd = &udev->curr_nl_cmd; | 301 | pr_err(KERN_ERR "tcmu nl cmd %u/%d completion could not find device with dev id %u.\n", |
| 302 | completed_cmd, rc, dev_id); | ||
| 303 | ret = -ENODEV; | ||
| 304 | goto unlock; | ||
| 305 | } | ||
| 306 | list_del(&nl_cmd->nl_list); | ||
| 298 | 307 | ||
| 299 | pr_debug("genl cmd done got id %d curr %d done %d rc %d\n", dev_id, | 308 | pr_debug("%s genl cmd done got id %d curr %d done %d rc %d\n", |
| 300 | nl_cmd->cmd, completed_cmd, rc); | 309 | udev->name, dev_id, nl_cmd->cmd, completed_cmd, rc); |
| 301 | 310 | ||
| 302 | if (nl_cmd->cmd != completed_cmd) { | 311 | if (nl_cmd->cmd != completed_cmd) { |
| 303 | printk(KERN_ERR "Mismatched commands (Expecting reply for %d. Current %d).\n", | 312 | pr_err("Mismatched commands on %s (Expecting reply for %d. Current %d).\n", |
| 304 | completed_cmd, nl_cmd->cmd); | 313 | udev->name, completed_cmd, nl_cmd->cmd); |
| 305 | ret = -EINVAL; | 314 | ret = -EINVAL; |
| 306 | } else { | 315 | goto unlock; |
| 307 | nl_cmd->status = rc; | ||
| 308 | } | 316 | } |
| 309 | 317 | ||
| 310 | spin_unlock(&udev->nl_cmd_lock); | 318 | nl_cmd->status = rc; |
| 311 | if (!is_removed) | 319 | complete(&nl_cmd->complete); |
| 312 | target_undepend_item(&dev->dev_group.cg_item); | 320 | unlock: |
| 313 | if (!ret) | 321 | mutex_unlock(&tcmu_nl_cmd_mutex); |
| 314 | complete(&nl_cmd->complete); | ||
| 315 | return ret; | 322 | return ret; |
| 316 | } | 323 | } |
| 317 | 324 | ||
| @@ -1258,7 +1265,6 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) | |||
| 1258 | timer_setup(&udev->cmd_timer, tcmu_cmd_timedout, 0); | 1265 | timer_setup(&udev->cmd_timer, tcmu_cmd_timedout, 0); |
| 1259 | 1266 | ||
| 1260 | init_waitqueue_head(&udev->nl_cmd_wq); | 1267 | init_waitqueue_head(&udev->nl_cmd_wq); |
| 1261 | spin_lock_init(&udev->nl_cmd_lock); | ||
| 1262 | 1268 | ||
| 1263 | INIT_RADIX_TREE(&udev->data_blocks, GFP_KERNEL); | 1269 | INIT_RADIX_TREE(&udev->data_blocks, GFP_KERNEL); |
| 1264 | 1270 | ||
| @@ -1544,10 +1550,10 @@ static void tcmu_init_genl_cmd_reply(struct tcmu_dev *udev, int cmd) | |||
| 1544 | return; | 1550 | return; |
| 1545 | 1551 | ||
| 1546 | relock: | 1552 | relock: |
| 1547 | spin_lock(&udev->nl_cmd_lock); | 1553 | mutex_lock(&tcmu_nl_cmd_mutex); |
| 1548 | 1554 | ||
| 1549 | if (nl_cmd->cmd != TCMU_CMD_UNSPEC) { | 1555 | if (nl_cmd->cmd != TCMU_CMD_UNSPEC) { |
| 1550 | spin_unlock(&udev->nl_cmd_lock); | 1556 | mutex_unlock(&tcmu_nl_cmd_mutex); |
| 1551 | pr_debug("sleeping for open nl cmd\n"); | 1557 | pr_debug("sleeping for open nl cmd\n"); |
| 1552 | wait_event(udev->nl_cmd_wq, (nl_cmd->cmd == TCMU_CMD_UNSPEC)); | 1558 | wait_event(udev->nl_cmd_wq, (nl_cmd->cmd == TCMU_CMD_UNSPEC)); |
| 1553 | goto relock; | 1559 | goto relock; |
| @@ -1555,9 +1561,13 @@ relock: | |||
| 1555 | 1561 | ||
| 1556 | memset(nl_cmd, 0, sizeof(*nl_cmd)); | 1562 | memset(nl_cmd, 0, sizeof(*nl_cmd)); |
| 1557 | nl_cmd->cmd = cmd; | 1563 | nl_cmd->cmd = cmd; |
| 1564 | nl_cmd->udev = udev; | ||
| 1558 | init_completion(&nl_cmd->complete); | 1565 | init_completion(&nl_cmd->complete); |
| 1566 | INIT_LIST_HEAD(&nl_cmd->nl_list); | ||
| 1567 | |||
| 1568 | list_add_tail(&nl_cmd->nl_list, &tcmu_nl_cmd_list); | ||
| 1559 | 1569 | ||
| 1560 | spin_unlock(&udev->nl_cmd_lock); | 1570 | mutex_unlock(&tcmu_nl_cmd_mutex); |
| 1561 | } | 1571 | } |
| 1562 | 1572 | ||
| 1563 | static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) | 1573 | static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) |
| @@ -1574,11 +1584,11 @@ static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) | |||
| 1574 | pr_debug("sleeping for nl reply\n"); | 1584 | pr_debug("sleeping for nl reply\n"); |
| 1575 | wait_for_completion(&nl_cmd->complete); | 1585 | wait_for_completion(&nl_cmd->complete); |
| 1576 | 1586 | ||
| 1577 | spin_lock(&udev->nl_cmd_lock); | 1587 | mutex_lock(&tcmu_nl_cmd_mutex); |
| 1578 | nl_cmd->cmd = TCMU_CMD_UNSPEC; | 1588 | nl_cmd->cmd = TCMU_CMD_UNSPEC; |
| 1579 | ret = nl_cmd->status; | 1589 | ret = nl_cmd->status; |
| 1580 | nl_cmd->status = 0; | 1590 | nl_cmd->status = 0; |
| 1581 | spin_unlock(&udev->nl_cmd_lock); | 1591 | mutex_unlock(&tcmu_nl_cmd_mutex); |
| 1582 | 1592 | ||
| 1583 | wake_up_all(&udev->nl_cmd_wq); | 1593 | wake_up_all(&udev->nl_cmd_wq); |
| 1584 | 1594 | ||
