[Devel] [PATCH] target: add an user-mode helper to handle changes of a group state
Andrei Vagin
avagin at openvz.org
Wed Jan 17 03:30:08 MSK 2018
An user-mode helper is a user command, which is executed before changing
a group state. It allows userspace to run required actions to handle a
new state.
For example, our storage doesn't allow to open one file from a few
nodes, so when a target is switched from standby to active, we have to
get a lease to an image file and to attach it to a ploop device.
The usermode helper is executed with this set of arguments:
TG_PT_Group ID prev_state new_state {explicit/implicit}
for example:
default_tg_pt_gp 0 Standby Active/NonOptimized explicit
Here is an example how to set and cleanup a helper:
$ cd /sys/kernel/config/target/core/
$ echo -n /usr/sbin/vstrorage_iscsi_alua > \
fileio_1/iqn.2014-06.com.vstorage:test-2/alua/default_tg_pt_gp/user_helper
$ echo -n - > fileio_1/iqn.2014-06.com.vstorage:test-2/alua/default_tg_pt_gp/user_helper
Signed-off-by: Andrei Vagin <avagin at openvz.org>
---
drivers/target/target_core_alua.c | 84 +++++++++++++++++++++++++++++++++++
drivers/target/target_core_alua.h | 4 ++
drivers/target/target_core_configfs.c | 17 +++++++
include/target/target_core_base.h | 1 +
4 files changed, 106 insertions(+)
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index a735425..a88a51d 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -31,6 +31,7 @@
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <asm/unaligned.h>
+#include <linux/kmod.h>
#include <target/target_core_base.h>
#include <target/target_core_backend.h>
@@ -1027,6 +1028,44 @@ static void core_alua_do_transition_ua(struct t10_alua_tg_pt_gp *tg_pt_gp)
spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
}
+static int core_alua_usermode_helper(struct t10_alua_tg_pt_gp *tg_pt_gp, int new_state, int explicit)
+{
+ char *envp[] = { "HOME=/",
+ "TERM=linux",
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+ NULL };
+ char *argv[7] = {}, str_id[6];
+ int ret;
+
+ if (!tg_pt_gp->tg_pt_gp_usermode_helper)
+ return 0;
+
+ mutex_lock(&tg_pt_gp->tg_pt_gp_transition_mutex);
+ if (!tg_pt_gp->tg_pt_gp_usermode_helper) {
+ mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex);
+ return 0;
+ }
+ argv[0] = kstrdup(tg_pt_gp->tg_pt_gp_usermode_helper, GFP_KERNEL);
+ mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex);
+
+ if (argv[0] == NULL)
+ return -ENOMEM;
+
+ snprintf(str_id, sizeof(str_id), "%hu", tg_pt_gp->tg_pt_gp_id);
+ argv[1] = config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item);
+ argv[2] = str_id;
+ argv[3] = core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_access_state);
+ argv[4] = core_alua_dump_state(new_state);
+ argv[5] = (explicit) ? "explicit" : "implicit";
+ argv[6] = NULL;
+
+ ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC | UMH_KILLABLE);
+ pr_debug("helper command: %s exit code %u (0x%x)\n",
+ argv[0], (ret >> 8) & 0xff, ret);
+ kfree(argv[0]);
+ return ret;
+}
+
static int core_alua_do_transition_tg_pt(
struct t10_alua_tg_pt_gp *tg_pt_gp,
int new_state,
@@ -1034,6 +1073,9 @@ static int core_alua_do_transition_tg_pt(
{
int prev_state;
+ if (core_alua_usermode_helper(tg_pt_gp, new_state, explicit))
+ return -EAGAIN;
+
mutex_lock(&tg_pt_gp->tg_pt_gp_transition_mutex);
/* Nothing to be done here */
if (tg_pt_gp->tg_pt_gp_alua_access_state == new_state) {
@@ -1682,6 +1724,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev,
tg_pt_gp->tg_pt_gp_nonop_delay_msecs = ALUA_DEFAULT_NONOP_DELAY_MSECS;
tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS;
tg_pt_gp->tg_pt_gp_implicit_trans_secs = ALUA_DEFAULT_IMPLICIT_TRANS_SECS;
+ tg_pt_gp->tg_pt_gp_usermode_helper = NULL;
/*
* Enable all supported states
@@ -1839,6 +1882,8 @@ void core_alua_free_tg_pt_gp(
}
spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ kfree(tg_pt_gp->tg_pt_gp_usermode_helper);
+
kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
}
@@ -2167,6 +2212,45 @@ ssize_t core_alua_store_trans_delay_msecs(
return count;
}
+ssize_t core_alua_show_user_helper(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ ssize_t len;
+
+ mutex_lock(&tg_pt_gp->tg_pt_gp_transition_mutex);
+ if (!tg_pt_gp->tg_pt_gp_usermode_helper)
+ len = 0;
+ else
+ len = sprintf(page, "%s\n", tg_pt_gp->tg_pt_gp_usermode_helper);
+ mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex);
+
+ return len;
+}
+
+ssize_t core_alua_store_user_helper(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ char *h;
+
+ if (count == 1 && page[0] == '-') {
+ h = NULL;
+ } else {
+ h = kstrndup(page, count, GFP_KERNEL);
+ if (h == NULL)
+ return -ENOMEM;
+ }
+
+ mutex_lock(&tg_pt_gp->tg_pt_gp_transition_mutex);
+ kfree(tg_pt_gp->tg_pt_gp_usermode_helper);
+ tg_pt_gp->tg_pt_gp_usermode_helper = h;
+ mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex);
+
+ return count;
+}
+
ssize_t core_alua_show_implicit_trans_secs(
struct t10_alua_tg_pt_gp *tg_pt_gp,
char *page)
diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h
index 0a7d65e..7673ffe 100644
--- a/drivers/target/target_core_alua.h
+++ b/drivers/target/target_core_alua.h
@@ -137,6 +137,10 @@ extern ssize_t core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
char *);
extern ssize_t core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
const char *, size_t);
+extern ssize_t core_alua_show_user_helper(struct t10_alua_tg_pt_gp *,
+ char *);
+extern ssize_t core_alua_store_user_helper(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
extern ssize_t core_alua_show_implicit_trans_secs(struct t10_alua_tg_pt_gp *,
char *);
extern ssize_t core_alua_store_implicit_trans_secs(struct t10_alua_tg_pt_gp *,
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 5229bcf..7596801 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -2323,6 +2323,22 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs(
SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR);
+static ssize_t target_core_alua_tg_pt_gp_show_attr_user_helper(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_user_helper(tg_pt_gp, page);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_user_helper(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_user_helper(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(user_helper, S_IRUGO | S_IWUSR);
/*
* implicit_trans_secs
*/
@@ -2474,6 +2490,7 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {
&target_core_alua_tg_pt_gp_alua_write_metadata.attr,
&target_core_alua_tg_pt_gp_nonop_delay_msecs.attr,
&target_core_alua_tg_pt_gp_trans_delay_msecs.attr,
+ &target_core_alua_tg_pt_gp_user_helper.attr,
&target_core_alua_tg_pt_gp_implicit_trans_secs.attr,
&target_core_alua_tg_pt_gp_preferred.attr,
&target_core_alua_tg_pt_gp_tg_pt_gp_id.attr,
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 189b73b..12415c4 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -328,6 +328,7 @@ struct t10_alua_tg_pt_gp {
struct list_head tg_pt_gp_mem_list;
struct se_port *tg_pt_gp_alua_port;
struct se_node_acl *tg_pt_gp_alua_nacl;
+ char *tg_pt_gp_usermode_helper;
};
struct t10_alua_tg_pt_gp_member {
--
1.8.3.1
More information about the Devel
mailing list