@@ -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);
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@suse.com> --- drivers/target/target_core_user.c | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)