[Devel] [PATCH RH8] target: add an user-mode helper to handle changes of a group state
Andrey Zhadchenko
andrey.zhadchenko at virtuozzo.com
Mon Apr 26 10:18:32 MSK 2021
From: Andrei Vagin <avagin at openvz.org>
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 several
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>
++++++++++
target: pass a device name to an alua user helper
Now the helper is executed with this list of arguments:
TG_PT_Group ID prev_state new_state {explicit/implicit} dev_name
For exmaple:
default_tg_pt_gp 0 Active/Optimized Standby explicit iqn.2014-06.com.vstorage:test-2
Signed-off-by: Andrei Vagin <avagin at openvz.org>
++++++++++
target: call alua helper before reporting group states to initiator
An alua helper is called with the same set of arguments as it is called
when a group state is changed, but the fourth argument will be "Read".
For example:
default_tg_pt_gp 0 Active/Optimized Read implicit iqn.2014-06.com.vstorage:test-1
Signed-off-by: Andrei Vagin <avagin at openvz.org>
++++++++++
target: move alua user helper from group to device
We added this helper to tune a device backing store (to set a correct
delta for a ploop device). It is executed when a group state is changed.
In this case, there is no difference where it is placed. But now we
understand, that we need to run this helper before reporting group
states to an initiator. It will be used to sync groups with other
targets in a cluster. We have to guaranty that only one target reports
the Active/Optimize state. And in this case, it looks better if a user
helper will be set per device.
How to use:
echo -n /usr/sbin/vstorage-alua-helper > \
/sys/kernel/config/target/core/iblock_0/iqn.2014-06.com.vstorage\:test-1/alua_user_helper
Signed-off-by: Andrei Vagin <avagin at openvz.org>
+++++++
target: rename user_helper back to alua_user_helper
After the last rebase, alua_user_helper was renamed into user_helper by
mistake.
https://pmc.acronis.com/browse/VSTOR-12238
Signed-off-by: Andrei Vagin <avagin at openvz.org>
Rebased to vz8 the following commits:
fd0aa40ecfa7a2b6285ea9e81803d2bfc1ca5e83 (target: add an user-mode helper to handle changes of a group state)
6264f46fc9a882b56a146176938349bc11f6906c (target: pass a device name to an alua user helper)
d5714465b67a6226a82f214a5809eb5dc2fb5910 (target: move alua user helper from group to device)
530d5853ba4fb59b22d3b58ab3da8dc43452ad3e (target: call alua helper before reporting group states to initiator)
c7326404fa9f9eb1211304c80051dc8514063330 (target: rename user_helper back to alua_user_helper)
Merged all commits into one, since most of them are fixups rather than new
functionality.
Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
---
drivers/target/target_core_alua.c | 66 +++++++++++++++++++++++++++++++++--
drivers/target/target_core_alua.h | 4 +++
drivers/target/target_core_configfs.c | 17 +++++++++
include/target/target_core_base.h | 2 ++
4 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 893f1fe..79ca506 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -33,6 +33,7 @@
#include <linux/fs.h>
#include <scsi/scsi_proto.h>
#include <asm/unaligned.h>
+#include <linux/kmod.h>
#include <target/target_core_base.h>
#include <target/target_core_backend.h>
@@ -140,6 +141,8 @@ static void __target_attach_tg_pt_gp(struct se_lun *lun,
return 0;
}
+static int core_alua_usermode_helper(struct t10_alua_tg_pt_gp *tg_pt_gp,
+ struct se_device *l_dev, int new_state, int explicit);
/*
* REPORT_TARGET_PORT_GROUPS
*
@@ -174,6 +177,8 @@ static void __target_attach_tg_pt_gp(struct se_lun *lun,
if (!buf)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ core_alua_usermode_helper(dev->t10_alua.default_tg_pt_gp, dev, -1, 0);
+
spin_lock(&dev->t10_alua.tg_pt_gps_lock);
list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
tg_pt_gp_list) {
@@ -1013,13 +1018,46 @@ static void core_alua_queue_state_change_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,
+ struct se_device *l_dev, int new_state, int explicit)
+{
+ char *envp[] = { "HOME=/",
+ "TERM=linux",
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+ NULL };
+ char *argv[8] = {}, str_id[6];
+ int ret;
+
+ if (!l_dev->alua_user_helper[0])
+ return 0;
+
+ argv[0] = l_dev->alua_user_helper;
+ 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] = new_state < 0 ? "Read" : core_alua_dump_state(new_state);
+ argv[5] = (explicit) ? "explicit" : "implicit";
+ argv[6] = config_item_name(&l_dev->dev_group.cg_item);
+ argv[7] = 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);
+ return ret;
+}
+
static int core_alua_do_transition_tg_pt(
struct t10_alua_tg_pt_gp *tg_pt_gp,
+ struct se_device *l_dev,
int new_state,
int explicit)
{
int prev_state;
+ if (core_alua_usermode_helper(tg_pt_gp, l_dev, 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) {
@@ -1128,7 +1166,7 @@ int core_alua_do_port_transition(
*/
l_tg_pt_gp->tg_pt_gp_alua_lun = l_lun;
l_tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl;
- rc = core_alua_do_transition_tg_pt(l_tg_pt_gp,
+ rc = core_alua_do_transition_tg_pt(l_tg_pt_gp, l_dev,
new_state, explicit);
atomic_dec_mb(&lu_gp->lu_gp_ref_cnt);
return rc;
@@ -1177,7 +1215,7 @@ int core_alua_do_port_transition(
* core_alua_do_transition_tg_pt() will always return
* success.
*/
- rc = core_alua_do_transition_tg_pt(tg_pt_gp,
+ rc = core_alua_do_transition_tg_pt(tg_pt_gp, l_dev,
new_state, explicit);
spin_lock(&dev->t10_alua.tg_pt_gps_lock);
@@ -2111,6 +2149,30 @@ ssize_t core_alua_store_trans_delay_msecs(
return count;
}
+ssize_t core_alua_show_user_helper(
+ struct se_device *dev,
+ char *page)
+{
+ return sprintf(page, "%s\n", dev->alua_user_helper);
+}
+
+ssize_t core_alua_store_user_helper(
+ struct se_device *dev,
+ const char *page,
+ size_t count)
+{
+ if (count == 1 && page[0] == '-') {
+ dev->alua_user_helper[0] = 0;
+ } else if (count > ALUA_USER_HELPER_LEN - 1) {
+ return -EINVAL;
+ } else {
+ memcpy(dev->alua_user_helper, page, count);
+ dev->alua_user_helper[count] = 0;
+ }
+
+ 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 fc9637c..9467698 100644
--- a/drivers/target/target_core_alua.h
+++ b/drivers/target/target_core_alua.h
@@ -127,6 +127,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 se_device *,
+ char *);
+extern ssize_t core_alua_store_user_helper(struct se_device *,
+ 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 a517db6..aea84f5 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -2199,6 +2199,21 @@ static ssize_t target_dev_enable_store(struct config_item *item,
return count;
}
+static ssize_t target_dev_alua_user_helper_show(struct config_item *item, char *page)
+{
+ struct se_device *dev = to_device(item);
+
+ return core_alua_show_user_helper(dev, page);
+}
+
+static ssize_t target_dev_alua_user_helper_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_device *dev = to_device(item);
+
+ return core_alua_store_user_helper(dev, page, count);
+}
+
static ssize_t target_dev_alua_lu_gp_show(struct config_item *item, char *page)
{
struct se_device *dev = to_device(item);
@@ -2470,6 +2485,7 @@ static ssize_t target_dev_lba_map_store(struct config_item *item,
CONFIGFS_ATTR(target_dev_, enable);
CONFIGFS_ATTR(target_dev_, alua_lu_gp);
CONFIGFS_ATTR(target_dev_, lba_map);
+CONFIGFS_ATTR(target_dev_, alua_user_helper);
static struct configfs_attribute *target_core_dev_attrs[] = {
&target_dev_attr_info,
@@ -2479,6 +2495,7 @@ static ssize_t target_dev_lba_map_store(struct config_item *item,
&target_dev_attr_enable,
&target_dev_attr_alua_lu_gp,
&target_dev_attr_lba_map,
+ &target_dev_attr_alua_user_helper,
NULL,
};
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 2622fd6..fc5caf0 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -854,6 +854,8 @@ struct se_device {
unsigned char dev_alias[SE_DEV_ALIAS_LEN];
#define SE_UDEV_PATH_LEN 512 /* must be less than PAGE_SIZE */
unsigned char udev_path[SE_UDEV_PATH_LEN];
+#define ALUA_USER_HELPER_LEN 512 /* must be less than PAGE_SIZE */
+ char alua_user_helper[ALUA_USER_HELPER_LEN];
/* Pointer to template of function pointers for transport */
const struct target_backend_ops *transport;
struct se_lun xcopy_lun;
--
1.8.3.1
More information about the Devel
mailing list