[Devel] [PATCH RHEL8 COMMIT] target: add an user-mode helper to handle changes of a group state
Konstantin Khorenko
khorenko at virtuozzo.com
Fri Apr 30 14:40:04 MSK 2021
The commit is pushed to "branch-rh8-4.18.0-240.1.1.vz8.5.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh8-4.18.0-240.1.1.vz8.5.24
------>
commit 693732061d6d4532a1d1baf934bd81e45bdf0ffb
Author: Andrei Vagin <avagin at openvz.org>
Date: Fri Apr 30 14:40:04 2021 +0300
target: add an user-mode helper to handle changes of a group state
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 893f1fe8e373..79ca5068d585 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 @@ target_emulate_report_referrals(struct se_cmd *cmd)
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 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
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 fc9637cce825..9467698e7b09 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 a517db654ce5..aea84f5224a6 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 @@ CONFIGFS_ATTR(target_dev_, udev_path);
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 struct configfs_attribute *target_core_dev_attrs[] = {
&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 2622fd654bec..fc5caf03c752 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;
More information about the Devel
mailing list