#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;
 
                 "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,
        }
        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",
 
        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",
        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;