This patch added four functions: tcmu_pr_info_clear_reg() would delete a registration from a struct tcmu_pr_info, tcmu_pr_info_rsv_clear() would clear the reservation, tcmu_is_rsv_holder() would check whether the registration is a reservation holder. Then tcmu_pr_info_unregister_reg() would call the functions above to unregister the registration. Signed-off-by: Zhu Lingshan <lszhu@xxxxxxxx> --- drivers/target/target_core_user.c | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 5d0da54072cd..a6e951f04065 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -41,6 +41,7 @@ #include <target/target_core_backend.h> #include <linux/target_core_user.h> +#include "target_core_pr.h" /* * Define a shared-memory interface for LIO to pass SCSI commands and @@ -2539,6 +2540,80 @@ tcmu_execute_pr_register_new(struct tcmu_pr_info *pr_info, u64 old_key, return ret; } +static bool tcmu_is_rsv_holder(struct tcmu_pr_rsv *rsv, + struct tcmu_pr_reg *reg, bool *rsv_is_all_reg) +{ + if (!rsv || !reg) { + WARN_ON(1); + return false; + } + if ((rsv->type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) + || (rsv->type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { + /* any registeration is a reservation holder */ + if (rsv_is_all_reg) + *rsv_is_all_reg = true; + return true; + } + + if (rsv_is_all_reg) + *rsv_is_all_reg = false; + + if ((rsv->key == reg->key) + && !strncmp(rsv->it_nexus, reg->it_nexus, + ARRAY_SIZE(rsv->it_nexus))) { + return true; + } + + return false; +} + +static void tcmu_pr_info_clear_reg(struct tcmu_pr_info *pr_info, + struct tcmu_pr_reg *reg) +{ + list_del(®->regs_node); + pr_info->num_regs--; + + pr_debug("deleted pr_info reg: 0x%llx\n", reg->key); + + kfree(reg); +} + +static void tcmu_pr_info_rsv_clear(struct tcmu_pr_info *pr_info) +{ + kfree(pr_info->rsv); + pr_info->rsv = NULL; + + pr_debug("pr_info rsv cleared\n"); +} + +static int tcmu_pr_info_unregister_reg(struct tcmu_pr_info *pr_info, + struct tcmu_pr_reg *reg) +{ + struct tcmu_pr_rsv *rsv; + bool all_reg = false; + + rsv = pr_info->rsv; + if (rsv && tcmu_is_rsv_holder(rsv, reg, &all_reg)) { + /* + * If the persistent reservation holder is more than one I_T + * nexus, the reservation shall not be released until the + * registrations for all persistent reservation holder I_T + * nexuses are removed. + */ + if (!all_reg || (pr_info->num_regs == 1)) { + pr_warn("implicitly releasing PR of type %d", + rsv->type); + pr_warn("on unregister I_T Nexus %s\n", + reg->it_nexus); + tcmu_pr_info_rsv_clear(pr_info); + } + } + + tcmu_pr_info_clear_reg(pr_info, reg); + + return 0; +} + static int tcmu_configure_device(struct se_device *dev) { struct tcmu_dev *udev = TCMU_DEV(dev); -- 2.17.1 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html