Skip to content

Commit

Permalink
scsi: tcmu: add module wide block/reset_netlink support
Browse files Browse the repository at this point in the history
This patch based on Xiubo's patches adds 2 tcmu attr to block and reset the
netlink interface. It's used during userspace daemon reinitialization after
the daemon has crashed while there is outstanding nl requests. The daemon
can block the nl interface, kill outstanding requests in the kernel and
then reopen the netlink socket and unblock it to allow new requests.

[mkp: typo]

Signed-off-by: Mike Christie <mchristi@redhat.com>
Tested-by: Xiubo Li <xiubli@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Mike Christie authored and Martin K. Petersen committed Jun 26, 2018
1 parent 06add77 commit bdaeedc
Showing 1 changed file with 97 additions and 3 deletions.
100 changes: 97 additions & 3 deletions drivers/target/target_core_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
#define TCMU_GLOBAL_MAX_BLOCKS_DEF (512 * 1024)

static u8 tcmu_kern_cmd_reply_supported;
static u8 tcmu_netlink_blocked;

static struct device *tcmu_root_device;

Expand Down Expand Up @@ -255,6 +256,92 @@ MODULE_PARM_DESC(global_max_data_area_mb,
"Max MBs allowed to be allocated to all the tcmu device's "
"data areas.");

static int tcmu_get_block_netlink(char *buffer,
const struct kernel_param *kp)
{
return sprintf(buffer, "%s\n", tcmu_netlink_blocked ?
"blocked" : "unblocked");
}

static int tcmu_set_block_netlink(const char *str,
const struct kernel_param *kp)
{
int ret;
u8 val;

ret = kstrtou8(str, 0, &val);
if (ret < 0)
return ret;

if (val > 1) {
pr_err("Invalid block netlink value %u\n", val);
return -EINVAL;
}

tcmu_netlink_blocked = val;
return 0;
}

static const struct kernel_param_ops tcmu_block_netlink_op = {
.set = tcmu_set_block_netlink,
.get = tcmu_get_block_netlink,
};

module_param_cb(block_netlink, &tcmu_block_netlink_op, NULL, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(block_netlink, "Block new netlink commands.");

static int tcmu_fail_netlink_cmd(struct tcmu_nl_cmd *nl_cmd)
{
struct tcmu_dev *udev = nl_cmd->udev;

if (!tcmu_netlink_blocked) {
pr_err("Could not reset device's netlink interface. Netlink is not blocked.\n");
return -EBUSY;
}

if (nl_cmd->cmd != TCMU_CMD_UNSPEC) {
pr_debug("Aborting nl cmd %d on %s\n", nl_cmd->cmd, udev->name);
nl_cmd->status = -EINTR;
list_del(&nl_cmd->nl_list);
complete(&nl_cmd->complete);
}
return 0;
}

static int tcmu_set_reset_netlink(const char *str,
const struct kernel_param *kp)
{
struct tcmu_nl_cmd *nl_cmd, *tmp_cmd;
int ret;
u8 val;

ret = kstrtou8(str, 0, &val);
if (ret < 0)
return ret;

if (val != 1) {
pr_err("Invalid reset netlink value %u\n", val);
return -EINVAL;
}

mutex_lock(&tcmu_nl_cmd_mutex);
list_for_each_entry_safe(nl_cmd, tmp_cmd, &tcmu_nl_cmd_list, nl_list) {
ret = tcmu_fail_netlink_cmd(nl_cmd);
if (ret)
break;
}
mutex_unlock(&tcmu_nl_cmd_mutex);

return ret;
}

static const struct kernel_param_ops tcmu_reset_netlink_op = {
.set = tcmu_set_reset_netlink,
};

module_param_cb(reset_netlink, &tcmu_reset_netlink_op, NULL, S_IWUSR);
MODULE_PARM_DESC(reset_netlink, "Reset netlink commands.");

/* multicast group */
enum tcmu_multicast_groups {
TCMU_MCGRP_CONFIG,
Expand Down Expand Up @@ -303,8 +390,9 @@ static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd)
}
list_del(&nl_cmd->nl_list);

pr_debug("%s genl cmd done got id %d curr %d done %d rc %d\n",
udev->name, dev_id, nl_cmd->cmd, completed_cmd, rc);
pr_debug("%s genl cmd done got id %d curr %d done %d rc %d stat %d\n",
udev->name, dev_id, nl_cmd->cmd, completed_cmd, rc,
nl_cmd->status);

if (nl_cmd->cmd != completed_cmd) {
pr_err("Mismatched commands on %s (Expecting reply for %d. Current %d).\n",
Expand Down Expand Up @@ -1547,6 +1635,13 @@ static int tcmu_init_genl_cmd_reply(struct tcmu_dev *udev, int cmd)

mutex_lock(&tcmu_nl_cmd_mutex);

if (tcmu_netlink_blocked) {
mutex_unlock(&tcmu_nl_cmd_mutex);
pr_warn("Failing nl cmd %d on %s. Interface is blocked.\n", cmd,
udev->name);
return -EAGAIN;
}

if (nl_cmd->cmd != TCMU_CMD_UNSPEC) {
mutex_unlock(&tcmu_nl_cmd_mutex);
pr_warn("netlink cmd %d already executing on %s\n",
Expand Down Expand Up @@ -1583,7 +1678,6 @@ static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev)
mutex_lock(&tcmu_nl_cmd_mutex);
nl_cmd->cmd = TCMU_CMD_UNSPEC;
ret = nl_cmd->status;
nl_cmd->status = 0;
mutex_unlock(&tcmu_nl_cmd_mutex);

return ret;
Expand Down

0 comments on commit bdaeedc

Please sign in to comment.