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 <ava...@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 <ava...@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 <ava...@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 <ava...@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 <ava...@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 <ava...@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.zhadche...@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;
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to