From 9d61dc4b03362ce04e48925164fb9d3ecf0f2929 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 6 Nov 2015 03:23:46 +0000 Subject: [PATCH] Cluster SCSI state sync support From Bart Van Assche Prepared with help from Pralay Dakua git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6573 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- doc/Makefile | 2 + ...LM as a Distributed In-Memory Database.pdf | Bin 0 -> 148782 bytes scst/README.dlm | 166 ++ scst/include/scst.h | 77 + scst/include/scst_const.h | 4 + scst/src/Makefile | 7 + scst/src/dev_handlers/scst_vdisk.c | 144 +- scst/src/scst_dlm.c | 1458 +++++++++++++++++ scst/src/scst_dlm.h | 154 ++ scst/src/scst_lib.c | 13 +- scst/src/scst_no_dlm.c | 118 ++ scst/src/scst_pres.c | 50 +- scst/src/scst_pres.h | 25 + scst/src/scst_priv.h | 45 +- scst/src/scst_sysfs.c | 8 +- scst/src/scst_targ.c | 29 +- 16 files changed, 2261 insertions(+), 39 deletions(-) create mode 100644 doc/Using the DLM as a Distributed In-Memory Database.pdf create mode 100644 scst/README.dlm create mode 100644 scst/src/scst_dlm.c create mode 100644 scst/src/scst_dlm.h create mode 100644 scst/src/scst_no_dlm.c diff --git a/doc/Makefile b/doc/Makefile index d2b95bd76..c1b59b8cc 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -36,7 +36,9 @@ rtf: $(RTFS) $(COMMAND)rtf $(<) clean: + mv "Using the DLM as a Distributed In-Memory Database.pdf" "Using the DLM as a Distributed In-Memory Database.pdf_" rm -f *.txt *.html *.tex *.dvi *.ps *.pdf *.info *.lyx *.rtf + mv "Using the DLM as a Distributed In-Memory Database.pdf_" "Using the DLM as a Distributed In-Memory Database.pdf" extraclean: clean rm -f *.orig *.rej diff --git a/doc/Using the DLM as a Distributed In-Memory Database.pdf b/doc/Using the DLM as a Distributed In-Memory Database.pdf new file mode 100644 index 0000000000000000000000000000000000000000..19be45865a01b8e36c3df7b127dc4f824417b98a GIT binary patch literal 148782 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 fsCFb0GJa@79^QP@Fm literal 0 HcmV?d00001 diff --git a/scst/README.dlm b/scst/README.dlm new file mode 100644 index 000000000..435e6d8bb --- /dev/null +++ b/scst/README.dlm @@ -0,0 +1,166 @@ +Synchronization of the Persistent Reservation Information via the DLM +===================================================================== + +Introduction +------------ + +In an H.A. setup where multiple servers share data it is required that +the persistent reservation state is kept consistent across the cluster. +One possible approach is to use the DLM to keep the PR state synchronized +across nodes. Since the DLM can associate data with each DLM lock object, +DLM lock objects can be used to store PR data. The data that is associated +with a DLM lock object is called the Lock Value Block or LVB. The code in +scst_dlm.c uses the DLM to keep PR data synchronized across all nodes in +a cluster. + +Software Components +------------------- + +The following software components are needed by the code in scst_dlm.c: +* The DLM kernel driver (dlm.ko). This driver is only built if CONFIG_DLM + has been set. +* The DLM control daemon (dlm_controld.pcmk). This daemon passes cluster + node IDs and IP addresses to the DLM kernel driver via the configfs + interface of the DLM kernel driver. +* Corosync to manage cluster membership of the cluster nodes and to assign + a node ID to each cluster node. +* A facility to start the DLM control daemon, e.g. Pacemaker. + +On most Linux distributions the software packages that contain this software +have the names kernel, dlm, corosync and pacemaker. + +DLM Configuration +----------------- + +The DLM kernel module supports the TCP and SCTP communication protocols. An +advantage of SCTP for H.A. purposes is that it supports multihoming. One of +these protocols can be selected via the -r option of dlm_controld. +That option can be set via the "args" argument of the Pacemaker dlm_controld +resource. For more information, see also: +* The dlm_controld(8) man page. +* In the "Pacemaker 1.1, Clusters from Scratch" guide, the section "Configure + the Cluster for the DLM". +* The dlm_controld resource agent: /usr/lib/ocf/resource.d/pacemaker/controld + +Here is an example of how to set up a cluster with two nodes and how to +configure and start the DLM control daemon: + 1. If a network switch is present between the two nodes, enable IPv4 multicast + on that switch. + 2. Copy /etc/corosync/corosync.conf.example into /etc/corosync/corosync.conf + and edit that file. + 3. If a file /etc/default/corosync exists, enable Corosync in that file. + 4. Start Corosync: + systemctl start corosync || /etc/init.d/corosync start + 5. Check that all configured Corosync rings have two members: + corosync-cfgtool -s && { corosync-cmapctl | grep members; } + 6. Start pcsd: + systemctl start pcsd || /etc/init.d/pcsd start + 7. Set up cluster authentication: + pcs cluster auth centos7-vm centos7b-vm + 8. Start Pacemaker: + systemctl start pacemaker || /etc/init.d/pacemaker start + 9. If the cluster has only two nodes, disable the Pacemaker quorum policy and + disable STONITH: + crm_attribute -t crm_config -n no-quorum-policy -v ignore + crm_attribute -t crm_config -n stonith-enabled -v false +10. Check the cluster status: + pcs status +11. Create a Pacemaker resource for dlm_controld: + pcs resource delete dlm + pcs resource create dlm ocf:pacemaker:controld \ + args="-q0 -f0" allow_stonith_disabled=true \ + op monitor timeout=60 \ + --clone interleave=true +12. Check the Pacemaker status: + pcs status + +Startup and Shutdown +-------------------- + +The startup sequence is as follows: +* Load and configure SCST with cluster_mode = 0 and with all target ports + disabled. +* Enable cluster mode for all SCST devices that can be accessed through more + than one cluster node: + for x in /sys/kernel/scst_tgt/handlers/*/*/; do + echo 1 >$x/cluster_mode & + done + wait +* Start Corosync and Pacemaker. +* Wait until Pacemaker has reached the idle state: + pacemaker_dc_status() { + local dc + + dc="$(crmadmin -D 2>/dev/null | sed 's/Designated Controller is: //')" + [ -n "$dc" ] && + crmadmin -S "$dc" 2>/dev/null | + sed 's/^Status of crmd@[^[:blank:]]*:[[:blank:]]\([^[:blank:]]*\).*/\1/' + } + for ((i=0;i<300;i++)); do + [ "$(pacemaker_dc_status)" = "S_IDLE" ] && break + sleep 1 + done +* Enable SCST target ports. +* If no DLM resource has been configured in Pacemaker, start dlm_controld.pcmk + explicitly. + +The proper shutdown order is as follows: +* Tell SCST to stop accepting SCSI commands and wait until all initiators have + logged out: + for x in $(find /sys/kernel/scst_tgt/targets/ -name enabled); do + echo 0 > $x & + done + wait + while ls -Ad /sys/kernel/scst_tgt/targets/*/*/sessions/* >/dev/null 2>&1; do + sleep 1 + done +* Tell SCST to release the DLM lockspaces: + while grep -q '^1$' /sys/kernel/scst_tgt/devices/*/cluster_mode 2>/dev/null + do + for x in /sys/kernel/scst_tgt/devices/*/cluster_mode; do + { [ -e "$x" ] && echo 0 > "$x"; } & + done + wait + sleep 1 + done +* Stop Pacemaker and Corosync +* Unload the SCST kernel modules +* Unload the DLM kernel driver + +Lockspace names +--------------- + +The names of the DLM lockspaces used by SCST follow the following pattern: +scst- where t10_dev_id is the T10 device ID of the SCST device +associated with this lockspace. + +Notes +----- + +Since the lockspace name depends on the t10_dev_id it is not allowed to +change the t10_dev_id if cluster mode has been enabled. + +Testing +------- + +Two examples of test suites for the cluster PR support code are: +* The SCSI conformance tests in the libiscsi project. +* The Windows Cluster Validation Tests + (https://technet.microsoft.com/en-us/library/Cc726064.aspx). + +To do +----- + +Ensure that PREEMPT AND ABORT affects all cluster nodes instead of only the +cluster node that received this command. + +See also +-------- + +* Bart Van Assche, Using the DLM as a distributed in-memory database, Linux + Plumbers North America, Seattle, August 20, 2015 + (https://linuxplumbersconf.org/2015/ocw//system/presentations/2691/original/Using%20the%20DLM%20as%20a%20Distributed%20In-Memory%20Database.pdf). +* Andrew Beekhof, Pacemaker Configuration Explained, 2015 + (http://clusterlabs.org/doc/en-US/Pacemaker/1.1/html/Pacemaker_Explained/). +* Andrew Beekhof, Clusters from Scratch, 2015 + (http://clusterlabs.org/doc/en-US/Pacemaker/1.1-pcs/html/Clusters_from_Scratch/index.html). diff --git a/scst/include/scst.h b/scst/include/scst.h index 8d1940bd2..feb76eff7 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef CONFIG_SCST_MEASURE_LATENCY #include #endif @@ -1991,6 +1992,18 @@ struct scst_cmd_threads { int scst_set_thr_cpu_mask(struct scst_cmd_threads *cmd_threads, cpumask_t *cpu_mask); +struct scst_pr_dlm_data; + +/* + * DLM lock status block with completion for notifying completion of + * synchronous DLM lock operations. + */ +struct scst_lksb { + struct dlm_lksb lksb; + struct completion compl; + struct scst_pr_dlm_data *pr_dlm; +}; + /* * Used to execute cmd's in order of arrival, honoring SCSI task attributes */ @@ -2545,6 +2558,53 @@ struct scst_dev_registrant { /* 2 auxiliary fields used to rollback changes for errors, etc. */ struct list_head aux_list_entry; __be64 rollback_key; + + /* For registrant information managed via the DLM. */ + int dlm_idx; + struct scst_lksb lksb; + char lvb[PR_DLM_LVB_LEN]; +}; + +/** + * struct scst_cl_ops - Encapsulation of behavior that depends on cluster mode + * @pr_init: Initialize resources needed by one of the functions below. + * @pr_cleanup: Free resources allocated by one of the functions below. + * @pr_is_set: Whether or not one of the registrants holds a reservation. + * @pr_init_reg: Cluster-specific registrant initialization. + * @pr_rm_reg: Cluster-specific registrant cleanup. + * @pr_write_lock: Lock the PR data structures for write access. + * @pr_write_unlock: Unlock the PR data structures for write access. + * @reserved: Whether an initiator holds an SPC-2 reservation. + * @res_lock: Protect the SPC-2 reservation state against concurrent + * modifications. + * @res_unlock: Counterpart of @res_lock. + * @is_rsv_holder: Whether session @sess holds an SPC-2 reservation on @dev. + * @is_not_rsv_holder: Whether another session than @sess holds an SPC-2 + * reservation on @dev. + * @reserve: Apply an SPC-2 reservation for session @sess on @dev if + * @sess != NULL or clear that reservation if @ses == NULL. + */ +struct scst_cl_ops { + int (*pr_init)(struct scst_device *dev, const char *cl_dev_id); + void (*pr_cleanup)(struct scst_device *dev); + bool (*pr_is_set)(struct scst_device *dev); + void (*pr_init_reg)(struct scst_device *dev, + struct scst_dev_registrant *reg); + void (*pr_rm_reg)(struct scst_device *dev, + struct scst_dev_registrant *reg); + void (*pr_write_lock)(struct scst_device *dev, + struct scst_lksb *pr_lksb); + void (*pr_write_unlock)(struct scst_device *dev, + struct scst_lksb *pr_lksb); + + bool (*reserved)(struct scst_device *dev); + void (*res_lock)(struct scst_device *dev, struct scst_lksb *pr_lksb); + void (*res_unlock)(struct scst_device *dev, struct scst_lksb *pr_lksb); + bool (*is_rsv_holder)(struct scst_device *dev, + struct scst_session *sess); + bool (*is_not_rsv_holder)(struct scst_device *dev, + struct scst_session *sess); + void (*reserve)(struct scst_device *dev, struct scst_session *sess); }; /* @@ -2725,6 +2785,9 @@ struct scst_device { /* Set if reserved via the SPC-2 SCSI RESERVE command. */ struct scst_session *reserved_by; + /* Operations that depend on whether or not cluster mode is enabled */ + const struct scst_cl_ops *cl_ops; + /********************************************************************** * Persistent reservation fields. Protected as follows: * - Reading PR data must be protected via scst_pr_read_lock() / @@ -2745,12 +2808,21 @@ struct scst_device { /* Whether or not pr_file_name has been modified via sysfs. */ unsigned int pr_file_name_is_set:1; + /* + * Whether or not the PR state must be synchronized with other cluster + * nodes. + */ + unsigned int cluster_mode:1; + /* Persistent reservation type */ uint8_t pr_type; /* Persistent reservation scope */ uint8_t pr_scope; + /* Data structures for managing PR data via the DLM */ + struct scst_pr_dlm_data *pr_dlm; + /* Mutex to protect PR operations */ struct mutex dev_pr_mutex; @@ -5405,4 +5477,9 @@ void scst_path_put(struct nameidata *nd); #endif int scst_remove_file(const char *name); +int scst_pr_set_cluster_mode(struct scst_device *dev, bool cluster_mode, + const char *cl_dev_id); +int scst_pr_init_dev(struct scst_device *dev); +void scst_pr_clear_dev(struct scst_device *dev); + #endif /* __SCST_H */ diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index cdb4a4a6a..39a829b58 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -735,4 +735,8 @@ enum { E_TGT_PRIV_NOT_YET_SET = EBUSY }; +/* Size of the lock value block in the DLM PR lockspace */ +#define PR_DLM_LVB_LEN 256 + + #endif /* __SCST_CONST_H */ diff --git a/scst/src/Makefile b/scst/src/Makefile index 1110bbf93..351bb956e 100644 --- a/scst/src/Makefile +++ b/scst/src/Makefile @@ -48,6 +48,13 @@ scst-y += scst_sysfs.o scst-y += scst_mem.o scst-y += scst_debug.o scst-y += scst_pres.o +scst-y += scst_no_dlm.o +ifdef CONFIG_DLM +scst-y += scst_dlm.o +endif +ifdef CONFIG_DLM_MODULE +scst-y += scst_dlm.o +endif scst-y += scst_tg.o obj-$(CONFIG_SCST) += scst.o dev_handlers/ diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 1287a3769..6a5181061 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -396,6 +396,10 @@ static ssize_t vdisk_sysfs_removable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); static ssize_t vdev_sysfs_filename_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_cluster_mode_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_cluster_mode_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); static ssize_t vdisk_sysfs_resync_size_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); static ssize_t vdisk_sysfs_sync_store(struct kobject *kobj, @@ -483,6 +487,9 @@ static struct kobj_attribute vdisk_removable_attr = __ATTR(removable, S_IRUGO, vdisk_sysfs_removable_show, NULL); static struct kobj_attribute vdisk_filename_attr = __ATTR(filename, S_IRUGO, vdev_sysfs_filename_show, NULL); +static struct kobj_attribute vdisk_cluster_mode_attr = + __ATTR(cluster_mode, S_IWUSR|S_IRUGO, vdev_sysfs_cluster_mode_show, + vdev_sysfs_cluster_mode_store); static struct kobj_attribute vdisk_resync_size_attr = __ATTR(resync_size, S_IWUSR, NULL, vdisk_sysfs_resync_size_store); static struct kobj_attribute vdisk_sync_attr = @@ -540,6 +547,7 @@ static const struct attribute *vdisk_fileio_attrs[] = { &vdisk_o_direct_attr.attr, &vdisk_removable_attr.attr, &vdisk_filename_attr.attr, + &vdisk_cluster_mode_attr.attr, &vdisk_resync_size_attr.attr, &vdisk_sync_attr.attr, &vdev_t10_vend_id_attr.attr, @@ -567,6 +575,7 @@ static const struct attribute *vdisk_blockio_attrs[] = { &vdisk_removable_attr.attr, &vdisk_rotational_attr.attr, &vdisk_filename_attr.attr, + &vdisk_cluster_mode_attr.attr, &vdisk_resync_size_attr.attr, &vdisk_sync_attr.attr, &vdev_t10_vend_id_attr.attr, @@ -680,6 +689,7 @@ static struct scst_dev_type vdisk_file_devtype = { "filename, " "nv_cache, " "o_direct, " + "cluster_mode, " "read_only, " "removable, " "rotational, " @@ -734,6 +744,7 @@ static struct scst_dev_type vdisk_blk_devtype = { "dif_filename, " "filename, " "nv_cache, " + "cluster_mode, " "read_only, " "removable, " "rotational, " @@ -1648,6 +1659,9 @@ next: if (vdev_saved_mode_pages_enabled) vdev_load_mode_pages(virt_dev); + res = scst_pr_set_cluster_mode(dev, dev->cluster_mode, + virt_dev->t10_dev_id); + out: TRACE_EXIT(); return res; @@ -1664,6 +1678,8 @@ static void vdisk_detach(struct scst_device *dev) TRACE_DBG("virt_id %d", dev->virt_id); + scst_pr_set_cluster_mode(dev, false, virt_dev->t10_dev_id); + PRINT_INFO("Detached virtual device %s (\"%s\")", virt_dev->name, vdev_get_filename(virt_dev)); @@ -4437,14 +4453,16 @@ static int vdisk_ctrl_m_pg(unsigned char *p, int pcontrol, */ p[2] |= 7 << 5; /* TST */ #endif - p[2] |= 1 << 2; /* D_SENSE */ - p[2] |= 1 << 3; /* DPICZ */ - p[2] |= 1 << 4; /* TMF_ONLY */ - p[3] |= 0xF << 4; /* QUEUE ALGORITHM MODIFIER */ - p[3] |= 3 << 1; /* QErr */ - p[4] |= 1 << 3; /* SWP */ - p[5] |= 1 << 6; /* TAS */ - p[5] |= 0 << 7; /* ATO */ + if (!virt_dev->dev->cluster_mode) { + p[2] |= 1 << 2; /* D_SENSE */ + p[2] |= 1 << 3; /* DPICZ */ + p[2] |= 1 << 4; /* TMF_ONLY */ + p[3] |= 0xF << 4; /* QUEUE ALGORITHM MODIFIER */ + p[3] |= 3 << 1; /* QErr */ + p[4] |= 1 << 3; /* SWP */ + p[5] |= 1 << 6; /* TAS */ + p[5] |= 0 << 7; /* ATO */ + } break; case 2: /* default */ p[2] |= virt_dev->tst << 5; @@ -4920,6 +4938,13 @@ static enum compl_status_e vdisk_exec_mode_select(struct vdisk_cmd_params *p) TRACE_ENTRY(); virt_dev = cmd->dev->dh_priv; + if (cmd->dev->cluster_mode) { + PRINT_ERROR("MODE SELECT: not supported in cluster mode\n"); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); + goto out; + } + mselect_6 = (MODE_SELECT == cmd->cdb[0]); type = cmd->dev->type; @@ -8810,6 +8835,104 @@ out: return res; } +static ssize_t vdev_sysfs_cluster_mode_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_device *dev = container_of(kobj, struct scst_device, + dev_kobj); + + return sprintf(buf, "%d\n%s", dev->cluster_mode, + dev->cluster_mode ? + SCST_SYSFS_KEY_MARK "\n" : ""); +} + +static int vdev_sysfs_process_cluster_mode_store( + struct scst_sysfs_work_item *work) +{ + struct scst_device *dev = work->dev; + struct scst_vdisk_dev *virt_dev; + long clm; + int res; + + res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER); + if (res) + goto out; + + res = mutex_lock_interruptible(&scst_mutex); + if (res) + goto resume; + + /* + * This is safe since we hold a reference on dev_kobj and since + * scst_assign_dev_handler() waits until all dev_kobj references + * have been dropped before invoking .detach(). + */ + virt_dev = dev->dh_priv; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) + res = kstrtol(work->buf, 0, &clm); +#else + res = strict_strtol(work->buf, 0, &clm); +#endif + if (res) + goto unlock; + res = -EINVAL; + if (clm < 0 || clm > 1) + goto unlock; + if (clm != dev->cluster_mode) { + res = scst_pr_set_cluster_mode(dev, clm, virt_dev->t10_dev_id); + if (res) + goto unlock; + dev->cluster_mode = clm; + } else { + res = 0; + } + +unlock: + mutex_unlock(&scst_mutex); + +resume: + scst_resume_activity(); + +out: + kobject_put(&dev->dev_kobj); + + return res; +} + +static ssize_t vdev_sysfs_cluster_mode_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct scst_device *dev = container_of(kobj, struct scst_device, + dev_kobj); + struct scst_sysfs_work_item *work; + char *arg; + int res; + + TRACE_ENTRY(); + + res = -ENOMEM; + arg = kasprintf(GFP_KERNEL, "%.*s", (int)count, buf); + if (!arg) + goto out; + + res = scst_alloc_sysfs_work(vdev_sysfs_process_cluster_mode_store, + false, &work); + if (res) + goto out; + work->dev = dev; + swap(work->buf, arg); + kobject_get(&dev->dev_kobj); + res = scst_sysfs_queue_wait_work(work); + if (res) + goto out; + res = count; + +out: + kfree(arg); + TRACE_EXIT_RES(res); + return res; +} + static int vdisk_sysfs_process_resync_size_store( struct scst_sysfs_work_item *work) { @@ -9165,6 +9288,10 @@ static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj, dev = container_of(kobj, struct scst_device, dev_kobj); virt_dev = dev->dh_priv; + res = -EPERM; + if (dev->cluster_mode) + goto out; + write_lock(&vdisk_serial_rwlock); if ((count > sizeof(virt_dev->t10_dev_id)) || @@ -9198,6 +9325,7 @@ static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj, out_unlock: write_unlock(&vdisk_serial_rwlock); +out: TRACE_EXIT_RES(res); return res; } diff --git a/scst/src/scst_dlm.c b/scst/src/scst_dlm.c new file mode 100644 index 000000000..369c98c24 --- /dev/null +++ b/scst/src/scst_dlm.c @@ -0,0 +1,1458 @@ +/* + * Copyright (c) 2013 - 2014 Fusion-io, Inc. All rights reserved. + * Copyright (C) 2014 - 2015 SanDisk Corporation. + * + * Synchronization of persistent registration data with DLM lock value blocks. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#ifdef INSIDE_KERNEL_TREE +#include +#include +#else +#include "scst.h" +#include "scst_const.h" +#endif +#include "scst_priv.h" +#include "scst_pres.h" +#include "scst_dlm.h" + +static void scst_pr_dlm_cleanup(struct scst_device *dev); +static void scst_dlm_pre_bast(void *bastarg, int mode); +static void scst_dlm_post_bast(void *bastarg, int mode); +static void scst_dlm_post_ast(void *astarg); + +static inline void compile_time_size_checks(void) +{ + BUILD_BUG_ON(sizeof(struct pr_lvb) > PR_DLM_LVB_LEN); + BUILD_BUG_ON(sizeof(struct pr_lvb) != 20); + BUILD_BUG_ON(sizeof(struct pr_reg_lvb) > PR_DLM_LVB_LEN); + BUILD_BUG_ON(sizeof(struct pr_reg_lvb) != 240); +} + +static void scst_dlm_ast(void *astarg) +{ + struct scst_lksb *scst_lksb = astarg; + + complete(&scst_lksb->compl); +} + +/** + * scst_dlm_cancel - Synchronously cancel a pending dlm_lock() operation + */ +static int scst_dlm_cancel(dlm_lockspace_t *ls, struct scst_lksb *lksb, + int flags, const char *name) +{ + int res; + + res = dlm_unlock(ls, lksb->lksb.sb_lkid, + DLM_LKF_CANCEL | (flags & DLM_LKF_VALBLK), + &lksb->lksb, lksb); + if (res < 0) + goto out; + res = wait_for_completion_timeout(&lksb->compl, 10 * HZ); + +out: + return res; +} + +/** + * scst_dlm_lock_wait - Wait until a DLM lock has been granted + * @ls: DLM lock space. + * @mode: DLM lock mode. + * @lksb: DLM lock status block. + * @flags: DLM flags. + * @name: DLM lock name. Only required for non-conversion requests. + * @bast: AST to be invoked in case this lock blocks another one. + */ +static int scst_dlm_lock_wait(dlm_lockspace_t *ls, int mode, + struct scst_lksb *lksb, int flags, + const char *name, void (*bast)(void *, int)) +{ + int res; + + init_completion(&lksb->compl); + res = dlm_lock(ls, mode, &lksb->lksb, flags, + (void *)name, name ? strlen(name) : 0, 0, + scst_dlm_ast, lksb, bast); + if (res < 0) + goto out; + res = wait_for_completion_timeout(&lksb->compl, 60 * HZ); + if (res > 0) + res = lksb->lksb.sb_status; + else if (res == 0) + res = -ETIMEDOUT; + if (res < 0) { + int res2 = scst_dlm_cancel(ls, lksb, flags, name); + + WARN(res2 < 0, "canceling lock %s / %08x failed: %d\n", + name ? : "?", lksb->lksb.sb_lkid, res2); + } + +out: + return res; +} + +/** + * scst_dlm_unlock_wait - Discard a DLM lock + */ +static int scst_dlm_unlock_wait(dlm_lockspace_t *ls, struct scst_lksb *lksb) +{ + int res; + + sBUG_ON(!ls); + + init_completion(&lksb->compl); + res = dlm_unlock(ls, lksb->lksb.sb_lkid, 0, &lksb->lksb, lksb); + if (res < 0) + goto out; + res = wait_for_completion_timeout(&lksb->compl, 60 * HZ); + if (res > 0) { + res = lksb->lksb.sb_status; + if (res == -DLM_EUNLOCK || res == -DLM_ECANCEL) + res = 0; + } else if (res == 0) { + res = -ETIMEDOUT; + } + +out: + return res; +} + +/* Number of persistent reservation registrants. */ +static uint32_t scst_pr_num_regs(struct scst_device *dev) +{ + struct scst_dev_registrant *reg; + uint32_t num_regs = 0; + + lockdep_assert_pr_read_lock_held(dev); + + list_for_each_entry(reg, &dev->dev_registrants_list, + dev_registrants_list_entry) + num_regs++; + + return num_regs; +} + +/* DLM-specific registrant initialization. */ +static void scst_dlm_pr_init_reg(struct scst_device *dev, + struct scst_dev_registrant *reg) +{ + reg->lksb.lksb.sb_lvbptr = (void *)reg->lvb; + reg->lksb.lksb.sb_lkid = 0; + reg->dlm_idx = -1; +} + +static void scst_dlm_pr_rm_reg_ls(dlm_lockspace_t *ls, + struct scst_dev_registrant *reg) +{ + int res; + + if (!reg->lksb.lksb.sb_lkid) + return; + res = scst_dlm_unlock_wait(ls, ®->lksb); + WARN(res < 0, "scst_dlm_unlock_wait(%08x) failed (%d)", + reg->lksb.lksb.sb_lkid, res); + reg->lksb.lksb.sb_lkid = 0; + reg->dlm_idx = -1; +} + +/* DLM-specific registrant cleanup. */ +static void scst_dlm_pr_rm_reg(struct scst_device *dev, + struct scst_dev_registrant *reg) +{ + lockdep_assert_pr_write_lock_held(dev); + scst_dlm_pr_rm_reg_ls(dev->pr_dlm->ls, reg); +} + +/* Copy SPC-2 reservation state from the DLM LVB into @dev. */ +static bool scst_copy_res_from_dlm(struct scst_device *dev, struct pr_lvb *lvb) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + struct scst_session *dropped_res = NULL; + bool modified_lvb = false; + + spin_lock_bh(&dev->dev_lock); + pr_dlm->reserved_by_nodeid = be32_to_cpu(lvb->reserved_by_nodeid); + if (dev->reserved_by && + pr_dlm->reserved_by_nodeid != pr_dlm->local_nodeid) { + PRINT_WARNING("%s: dropping SPC-2 reservation for %s (due to" + " split-brain ?) because node %d holds a" + " reservation", dev->virt_name, + dev->reserved_by->initiator_name, + pr_dlm->reserved_by_nodeid); + swap(dev->reserved_by, dropped_res); + } + if (!dev->reserved_by && + pr_dlm->reserved_by_nodeid == pr_dlm->local_nodeid) { + PRINT_WARNING("%s: dropping SPC-2 reservation (due to restart" + " or split-brain ?) and triggering LVB update" + " because of inconstency (holder %d / not rsrvd)", + dev->virt_name, pr_dlm->reserved_by_nodeid); + pr_dlm->reserved_by_nodeid = 0; + lvb->reserved_by_nodeid = 0; + modified_lvb = true; + } + if (dev->reserved_by) + EXTRACHECKS_BUG_ON(pr_dlm->reserved_by_nodeid != + pr_dlm->local_nodeid); + else + EXTRACHECKS_BUG_ON(pr_dlm->reserved_by_nodeid == + pr_dlm->local_nodeid); + if (dropped_res) + scst_sess_get(dropped_res); + spin_unlock_bh(&dev->dev_lock); + + if (dropped_res) { + /* + * To do: something like + * scst_do_nexus_loss_sess(dropped_res, true); + */ + scst_sess_put(dropped_res); + } + + return modified_lvb; +} + +/* + * Update local PR and registrant information from the content of the DLM LVB's. + * Caller must hold PR_DATA_LOCK in PW mode. + * + * Returns -EINVAL if and only if an invalid lock value block has been + * encountered. + */ +static int scst_copy_from_dlm(struct scst_device *dev, dlm_lockspace_t *ls, + bool *modified_lvb) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + struct pr_lvb *lvb = (void *)pr_dlm->lvb; + struct scst_lksb *reg_lksb = NULL; + struct scst_dev_registrant *reg, *tmp_reg; + int i, res = -ENOMEM; + uint32_t nr_registrants; + void *reg_lvb_content = NULL; + + lockdep_assert_held(&pr_dlm->ls_mutex); + + nr_registrants = be32_to_cpu(lvb->nr_registrants); + if (nr_registrants) { + reg_lksb = vzalloc((sizeof(*reg_lksb) + PR_DLM_LVB_LEN) * + nr_registrants); + if (!reg_lksb) { + PRINT_ERROR("%s: failed to allocate %d * %zd bytes of" + " memory", __func__, nr_registrants, + sizeof(*reg_lksb) + PR_DLM_LVB_LEN); + goto out; + } + reg_lvb_content = (void *)reg_lksb + + nr_registrants * sizeof(*reg_lksb); + } + + for (i = 0; i < nr_registrants; i++) { + char reg_name[32]; + struct pr_reg_lvb *reg_lvb; + + snprintf(reg_name, sizeof(reg_name), PR_REG_LOCK, i); + reg_lvb = reg_lvb_content + i * PR_DLM_LVB_LEN; + reg_lksb[i].lksb.sb_lvbptr = (void *)reg_lvb; + res = scst_dlm_lock_wait(ls, DLM_LOCK_PW, ®_lksb[i], + DLM_LKF_VALBLK, reg_name, NULL); + if (res < 0) { + res = -EFAULT; + PRINT_ERROR("locking %s.%s failed", dev->virt_name, + reg_name); + goto cancel; + } else if (reg_lksb[i].lksb.sb_flags & DLM_SBF_VALNOTVALID) { + res = -EINVAL; + PRINT_WARNING("%s.%s has an invalid lock value block", + dev->virt_name, reg_name); + goto cancel; + } else if (reg_lvb->version != 1) { + res = -EPROTONOSUPPORT; + PRINT_ERROR("%s.%s.version = %d instead of 1", + dev->virt_name, reg_name, + reg_lvb->version); + goto cancel; + } + } + + *modified_lvb = scst_copy_res_from_dlm(dev, lvb); + + scst_pr_write_lock(dev); + + dev->pr_aptpl = lvb->pr_aptpl; + dev->pr_generation = be32_to_cpu(lvb->pr_generation); + dev->pr_is_set = lvb->pr_is_set; + dev->pr_type = lvb->pr_type; + dev->pr_scope = lvb->pr_scope; + dev->pr_holder = NULL; + + list_for_each_entry(reg, &dev->dev_registrants_list, + dev_registrants_list_entry) + scst_dlm_pr_rm_reg_ls(ls, reg); + + for (i = 0; i < nr_registrants; i++) { + struct pr_reg_lvb *reg_lvb; + uint16_t rel_tgt_id; + + reg_lvb = (struct pr_reg_lvb *)reg_lksb[i].lksb.sb_lvbptr; + rel_tgt_id = be16_to_cpu(reg_lvb->rel_tgt_id); +#if 0 + PRINT_INFO("Transport ID in %s." PR_REG_LOCK " (len %d):", + dev->virt_name, i, scst_tid_size(reg_lvb->tid)); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, + reg_lvb->tid, scst_tid_size(reg_lvb->tid), 1); +#endif + reg = scst_pr_find_reg(dev, reg_lvb->tid, rel_tgt_id); + if (reg && reg->key != reg_lvb->key) { + scst_pr_remove_registrant(dev, reg); + reg = NULL; + } + if (!reg) + reg = scst_pr_add_registrant(dev, reg_lvb->tid, + rel_tgt_id, reg_lvb->key, + false); + if (reg) { + scst_dlm_pr_rm_reg_ls(ls, reg); + reg->lksb.lksb.sb_lkid = reg_lksb[i].lksb.sb_lkid; + reg->dlm_idx = i; + memcpy(reg->lvb, reg_lvb_content, sizeof(reg->lvb)); + if (reg_lvb->is_holder) { + if (dev->pr_is_set) + scst_pr_clear_holder(dev); + scst_pr_set_holder(dev, reg, lvb->pr_scope, + lvb->pr_type); + } + } else { + PRINT_ERROR("pr_add_registrant %s." PR_REG_LOCK + " failed\n", dev->virt_name, i); + scst_dlm_unlock_wait(ls, ®_lksb[i]); + continue; + } + scst_dlm_lock_wait(ls, DLM_LOCK_CR, ®->lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, NULL, + NULL); + } + + /* Remove all registrants not found in any DLM LVB */ + list_for_each_entry_safe(reg, tmp_reg, &dev->dev_registrants_list, + dev_registrants_list_entry) + if (reg->lksb.lksb.sb_lkid == 0) + scst_pr_remove_registrant(dev, reg); + + scst_pr_write_unlock(dev); + + res = 0; + +out: + vfree(reg_lksb); + return res; + +cancel: + for (i = 0; i < nr_registrants; i++) + if (reg_lksb[i].lksb.sb_lkid) + scst_dlm_unlock_wait(ls, ®_lksb[i]); + + goto out; +} + +static struct scst_dev_registrant* +scst_get_reg_by_dlm_idx(struct scst_device *dev, int i) +{ + struct scst_dev_registrant *reg; + + lockdep_assert_pr_read_lock_held(dev); + + list_for_each_entry(reg, &dev->dev_registrants_list, + dev_registrants_list_entry) + if (reg->dlm_idx == i) + return reg; + + return NULL; +} + +static int scst_get_available_dlm_idx(struct scst_device *dev) +{ + int i = 0; + + lockdep_assert_pr_read_lock_held(dev); + + while (scst_get_reg_by_dlm_idx(dev, i)) + i++; + + return i; +} + +/* Copy SPC-2 reservation state for @dev into the DLM LVB @lvb. */ +static void scst_copy_res_to_dlm(struct scst_device *dev, struct pr_lvb *lvb) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + + spin_lock_bh(&dev->dev_lock); + lvb->reserved_by_nodeid = cpu_to_be32(pr_dlm->reserved_by_nodeid); + spin_unlock_bh(&dev->dev_lock); +} + +/* + * Update PR and registrant information in the DLM LVB's. Caller must hold + * PR_DATA_LOCK in PW mode. + */ +static void scst_copy_to_dlm(struct scst_device *dev, dlm_lockspace_t *ls) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + struct pr_lvb *lvb = (void *)pr_dlm->lvb; + struct pr_reg_lvb *reg_lvb; + struct scst_dev_registrant *reg; + int i, tid_size; + char reg_name[32]; + uint32_t nr_registrants; + + lockdep_assert_held(&pr_dlm->ls_mutex); + + scst_copy_res_to_dlm(dev, lvb); + + scst_pr_write_lock(dev); + + nr_registrants = scst_pr_num_regs(dev); + lvb->version = 1; + lvb->pr_is_set = dev->pr_is_set; + lvb->pr_type = dev->pr_type; + lvb->pr_scope = dev->pr_scope; + lvb->pr_aptpl = dev->pr_aptpl; + lvb->nr_registrants = cpu_to_be32(nr_registrants); + lvb->pr_generation = cpu_to_be32(dev->pr_generation); + + list_for_each_entry(reg, &dev->dev_registrants_list, + dev_registrants_list_entry) { + if (reg->dlm_idx >= nr_registrants) + scst_dlm_pr_rm_reg_ls(ls, reg); + if (reg->dlm_idx < 0) { + i = scst_get_available_dlm_idx(dev); + snprintf(reg_name, sizeof(reg_name), PR_REG_LOCK, i); + if (scst_dlm_lock_wait(ls, DLM_LOCK_NL, + ®->lksb, 0, reg_name, NULL) + >= 0) + reg->dlm_idx = i; + } + } + + list_for_each_entry(reg, &dev->dev_registrants_list, + dev_registrants_list_entry) { + if (WARN_ON(!reg->lksb.lksb.sb_lkid)) + continue; + snprintf(reg_name, sizeof(reg_name), PR_REG_LOCK, reg->dlm_idx); + if (scst_dlm_lock_wait(ls, DLM_LOCK_PW, ®->lksb, + DLM_LKF_VALBLK | DLM_LKF_CONVERT, + reg_name, NULL) >= 0) { + reg_lvb = (void *)reg->lksb.lksb.sb_lvbptr; + memset(reg->lvb, 0, sizeof(reg->lvb)); + reg_lvb->key = reg->key; + reg_lvb->rel_tgt_id = cpu_to_be16(reg->rel_tgt_id); + reg_lvb->version = 1; + reg_lvb->is_holder = dev->pr_holder == reg; + tid_size = scst_tid_size(reg->transport_id); +#if 0 + PRINT_INFO("Copying transport ID into %s." PR_REG_LOCK + " (len %d)", dev->virt_name, reg->dlm_idx, + tid_size); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, + 1, reg->transport_id, tid_size, 1); +#endif + if (WARN(tid_size > sizeof(reg_lvb->tid), + "tid_size %d > %zd\n", tid_size, + sizeof(reg_lvb->tid))) + tid_size = sizeof(reg_lvb->tid); + memcpy(reg_lvb->tid, reg->transport_id, tid_size); + scst_dlm_lock_wait(ls, DLM_LOCK_CR, ®->lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, + reg_name, NULL); + } else { + PRINT_ERROR("Failed to lock %s.%s", dev->virt_name, + reg_name); + } + } + + scst_pr_write_unlock(dev); +} + +/* + * Read the contents of a file, copy it into a buffer and terminate the buffer + * with '\0'. + */ +static int scst_read_file(const char *path, char *buf, int buf_len) +{ + struct file *f; + loff_t pos; + int ret; + + f = filp_open(path, 0, 0400); + if (IS_ERR(f)) { + ret = PTR_ERR(f); + goto out; + } + pos = 0; + ret = vfs_read(f, (char __force __user *)buf, buf_len, &pos); + if (ret >= 0) + buf[min(ret, buf_len - 1)] = '\0'; + filp_close(f, NULL); +out: + return ret; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) +struct scst_dlm_readdir_context { + struct dir_context ctx; + char *entries; +}; +#endif + +/* Append the name of each directory entry to the buffer @arg points to. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) +static int scst_dlm_filldir(void *arg, const char *name_arg, int name_len, + loff_t curr_pos, u64 inode, unsigned dtype) +#else +static int scst_dlm_filldir(struct dir_context *arg, const char *name_arg, + int name_len, loff_t curr_pos, u64 inode, + unsigned dtype) +#endif +{ + char *p, *q, name[64]; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) + char **entries = arg; +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) + struct scst_dlm_readdir_context *ctx = + container_of((struct dir_context *)arg, typeof(*ctx), ctx); +#else + struct scst_dlm_readdir_context *ctx = + container_of(arg, typeof(*ctx), ctx); +#endif + char **entries = &ctx->entries; +#endif + int i; + + snprintf(name, sizeof(name), "%.*s", name_len, name_arg); + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0 || !*entries) + goto out; + for (p = *entries; *p; p += strlen(p) + 1) + ; + i = p - *entries; + q = *entries; + *entries = krealloc(q, i + strlen(name) + 2, GFP_KERNEL); + if (!*entries) { + kfree(q); + goto out; + } + strcpy(*entries + i, name); + i += strlen(name); + (*entries)[i + 1] = '\0'; + +out: + return *entries ? 0 : -ENOMEM; +} + +/** + * scst_dlm_update_nodeids - Update the Corosync node ID array pr_dlm->nodeid[] + */ +static int scst_dlm_update_nodeids(struct scst_pr_dlm_data *pr_dlm) +{ + static const char comms_dir[] = "/sys/kernel/config/dlm/cluster/comms"; + struct file *comms; + char *p, *entries = kzalloc(1, GFP_KERNEL); + uint32_t nodeid, *new; + int i, ret, num_nodes; + char path[256], buf[64]; + + lockdep_assert_held(&pr_dlm->ls_mutex); + + num_nodes = 0; + + comms = filp_open(comms_dir, 0, 0400); + if (IS_ERR(comms)) { + ret = PTR_ERR(comms); + goto out; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) + ret = vfs_readdir(comms, scst_dlm_filldir, &entries); +#else + { + struct scst_dlm_readdir_context ctx = { + .ctx = { + .actor = scst_dlm_filldir, + }, + .entries = entries, + }; + ret = iterate_dir(comms, &ctx.ctx); + entries = ctx.entries; + } +#endif + filp_close(comms, NULL); + ret = -ENOMEM; + if (!entries) + goto out; + for (p = entries; *p; p += strlen(p) + 1) + num_nodes++; + new = krealloc(pr_dlm->nodeid, sizeof(*pr_dlm->nodeid) * num_nodes, + GFP_KERNEL); + if (!new) + goto out; + pr_dlm->nodeid = new; + pr_dlm->participants = num_nodes; + for (i = 0, p = entries; *p; i++, p += strlen(p) + 1) { + nodeid = simple_strtoul(p, NULL, 0); + snprintf(path, sizeof(path), "%s/%s/local", comms_dir, p); + if (scst_read_file(path, buf, sizeof(buf)) >= 0 && + strcmp(buf, "1\n") == 0) + pr_dlm->local_nodeid = nodeid; + pr_dlm->nodeid[i] = nodeid; + } + ret = 0; + +out: + kfree(entries); + return ret; +} + +/* + * Toggle all non-local DLM locks with name format @fmt from NL to PR and back + * to NL. + */ +static void scst_pr_toggle_lock(struct scst_pr_dlm_data *pr_dlm, + dlm_lockspace_t *ls, const char *fmt) +{ + struct scst_lksb lksb; + int i, res; + char lock_name[32]; + + memset(&lksb, 0, sizeof(lksb)); + for (i = 0; i < pr_dlm->participants; i++) { + if (pr_dlm->nodeid[i] == pr_dlm->local_nodeid) + continue; + snprintf(lock_name, sizeof(lock_name), fmt, pr_dlm->nodeid[i]); + lksb.lksb.sb_lkid = 0; + res = scst_dlm_lock_wait(ls, DLM_LOCK_PR, &lksb, 0, + lock_name, NULL); + if (res < 0) + PRINT_WARNING("Locking %s.%s failed (%d)", + pr_dlm->dev->virt_name, lock_name, res); + if (!lksb.lksb.sb_lkid) + continue; + scst_dlm_lock_wait(ls, DLM_LOCK_NL, &lksb, + DLM_LKF_CONVERT, lock_name, NULL); + scst_dlm_unlock_wait(ls, &lksb); + } +} + +/* Remove a lock from the local DLM lockspace instance. */ +static void scst_dlm_remove_lock(dlm_lockspace_t *ls, struct scst_lksb *lksb, + const char *name) +{ + if (!lksb->lksb.sb_lkid) + return; + scst_dlm_lock_wait(ls, DLM_LOCK_NL, lksb, DLM_LKF_CONVERT, name, + NULL); + scst_dlm_unlock_wait(ls, lksb); + lksb->lksb.sb_lkid = 0; +} + +static void scst_dlm_remove_locks(struct scst_pr_dlm_data *pr_dlm, + dlm_lockspace_t *ls) +{ + struct scst_device *dev = pr_dlm->dev; + struct scst_dev_registrant *reg; + + lockdep_assert_held(&pr_dlm->ls_mutex); + + scst_pr_write_lock(dev); + list_for_each_entry(reg, &dev->dev_registrants_list, + dev_registrants_list_entry) + scst_dlm_pr_rm_reg_ls(ls, reg); + scst_pr_write_unlock(dev); + + scst_dlm_remove_lock(ls, &pr_dlm->pre_join_lksb, NULL); + scst_dlm_remove_lock(ls, &pr_dlm->post_join_lksb, NULL); + scst_dlm_remove_lock(ls, &pr_dlm->pre_upd_lksb, NULL); + scst_dlm_remove_lock(ls, &pr_dlm->post_upd_lksb, NULL); + scst_dlm_remove_lock(ls, &pr_dlm->data_lksb, PR_DATA_LOCK); +} + +/* + * If two or more nodes are present in the cluster, tell each other node to + * update the local state information from the DLM lock value blocks. The + * caller must hold PR_LOCK in EX mode. + */ +static void scst_trigger_reread_lvb(struct scst_pr_dlm_data *const pr_dlm, + dlm_lockspace_t *ls) +{ + scst_pr_toggle_lock(pr_dlm, ls, PR_POST_UPDATE_LOCK); + scst_pr_toggle_lock(pr_dlm, ls, PR_PRE_UPDATE_LOCK); + scst_pr_toggle_lock(pr_dlm, ls, PR_POST_UPDATE_LOCK); +} + +/* + * If two or more nodes are present in the cluster, tell each other node to + * refresh the DLM lock value blocks. The caller must hold PR_LOCK in EX mode. + */ +static void scst_trigger_lvb_update(struct scst_pr_dlm_data *const pr_dlm, + dlm_lockspace_t *ls) +{ + PRINT_INFO("%s: about to trigger an LVB update", + pr_dlm->dev->virt_name); + scst_pr_toggle_lock(pr_dlm, ls, PR_POST_JOIN_LOCK); + scst_pr_toggle_lock(pr_dlm, ls, PR_PRE_JOIN_LOCK); + scst_pr_toggle_lock(pr_dlm, ls, PR_POST_JOIN_LOCK); + PRINT_INFO("%s: finished triggering an LVB update", + pr_dlm->dev->virt_name); +} + +static void dump_lockspace(const char *cl_dev_id) +{ + char *argv0 = kstrdup("/bin/bash", GFP_KERNEL); + char *argv1 = kstrdup("-c", GFP_KERNEL); + char *argv2 = kasprintf(GFP_KERNEL, + "{ echo lockspace-dump-start;" + " grep -aH '' /sys/kernel/debug/dlm/%s%s*;" + " echo lockspace-dump-end; } 2>&1 |" + " while read line; do logger \"$line\"; done", + SCST_DLM_LOCKSPACE_PFX, cl_dev_id); + char *argv[] = { argv0, argv1, argv2, NULL }; + char *envp[] = { + kstrdup("PATH=/usr/bin:/bin:/usr/sbin:/sbin", GFP_KERNEL), + NULL + }; + + + if (!argv[0] || !argv[1] || !argv[2] || !envp[0]) { + PRINT_ERROR("%s: out of memory", __func__); + goto out; + } + + PRINT_INFO("Invoking %s", argv2); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) + call_usermodehelper(argv0, argv, envp, UMH_WAIT_PROC); +#else + call_usermodehelper_fns(argv0, argv, envp, UMH_WAIT_PROC, NULL, NULL, + NULL); +#endif + +out: + kfree(envp[0]); + kfree(argv[2]); + kfree(argv[1]); + kfree(argv[0]); +} + +static void release_lockspace(dlm_lockspace_t *ls, const char *cl_dev_id) +{ + int res; + + res = dlm_release_lockspace(ls, 1); + if (res) { + PRINT_ERROR("releasing lockspace for %s failed: %d", + cl_dev_id, res); + dump_lockspace(cl_dev_id); + } + if (res == -EBUSY) { + /* + * Releasing a lockspace fails if one or more local instances + * of DLM locks still exist in the lockspace. If that + * happens try to release the lockspace forcibly. + */ + res = dlm_release_lockspace(ls, 2); + if (res) + PRINT_ERROR("forcibly releasing lockspace for %s" + " failed: %d", cl_dev_id, res); + } + if (res == 0) + PRINT_INFO("released lockspace for %s", cl_dev_id); +} + +/* Initialize DLM lockspace. */ +static dlm_lockspace_t *get_lockspace(struct scst_device *dev) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + dlm_lockspace_t *ls; + struct scst_lksb pr_lksb; + struct pr_lvb *lvb = (void *)pr_dlm->lvb; + char lsp_name[32], lock_name[32]; + int res; + bool modified_lvb = false; + + if (pr_dlm->ls || !pr_dlm->cl_dev_id || in_interrupt() || + time_is_after_jiffies(pr_dlm->latest_lscr_attempt + 1 * HZ)) + goto out; + + mutex_lock(&pr_dlm->ls_cr_mutex); + if (pr_dlm->ls) + goto out_unlock_ls_cr; + + pr_dlm->latest_lscr_attempt = jiffies; + + mutex_lock(&pr_dlm->ls_mutex); + + res = scst_dlm_update_nodeids(pr_dlm); + if (res < 0) { + PRINT_ERROR("scst_dlm_update_nodeids(%s) failed: %d", + dev->virt_name, res); + goto out_unlock_ls; + } + if (pr_dlm->participants == 0) + goto out_unlock_ls; + + snprintf(lsp_name, sizeof(lsp_name), "%s%s", SCST_DLM_LOCKSPACE_PFX, + pr_dlm->cl_dev_id); + res = scst_dlm_new_lockspace(lsp_name, strlen(lsp_name), &ls, + DLM_LSFL_NEWEXCL | DLM_LSFL_FS, + PR_DLM_LVB_LEN); + if (res) { + PRINT_ERROR("Creating DLM lockspace %s failed: %d", lsp_name, + res); + goto out_unlock_ls; + } + + PRINT_INFO("Created DLM lockspace %s for %s", lsp_name, dev->virt_name); + + memset(&pr_lksb, 0, sizeof(pr_lksb)); + res = scst_dlm_lock_wait(ls, DLM_LOCK_EX, &pr_lksb, 0, PR_LOCK, + NULL); + if (res < 0) + goto unlock_dlm_pr; + + snprintf(lock_name, sizeof(lock_name), PR_POST_JOIN_LOCK, + pr_dlm->local_nodeid); + pr_dlm->post_join_lksb.pr_dlm = pr_dlm; + res = scst_dlm_lock_wait(ls, DLM_LOCK_NL, + &pr_dlm->post_join_lksb, 0, lock_name, + scst_dlm_post_bast); + if (res < 0) + goto release_lockspace; + + snprintf(lock_name, sizeof(lock_name), PR_PRE_JOIN_LOCK, + pr_dlm->local_nodeid); + pr_dlm->pre_join_lksb.pr_dlm = pr_dlm; + res = scst_dlm_lock_wait(ls, DLM_LOCK_EX, + &pr_dlm->pre_join_lksb, 0, lock_name, + scst_dlm_pre_bast); + if (res < 0) + goto release_lockspace; + + res = scst_dlm_lock_wait(ls, DLM_LOCK_PW, &pr_dlm->data_lksb, + DLM_LKF_VALBLK, PR_DATA_LOCK, NULL); + if (res < 0) + goto release_lockspace; + + if (pr_dlm->data_lksb.lksb.sb_status & DLM_SBF_VALNOTVALID) { + PRINT_ERROR("%s.%s lock value block not valid", dev->virt_name, + PR_DATA_LOCK); + memset(pr_dlm->lvb, 0, sizeof(pr_dlm->lvb)); + } + + snprintf(lock_name, sizeof(lock_name), PR_POST_UPDATE_LOCK, + pr_dlm->local_nodeid); + pr_dlm->post_upd_lksb.pr_dlm = pr_dlm; + res = scst_dlm_lock_wait(ls, DLM_LOCK_NL, + &pr_dlm->post_upd_lksb, 0, lock_name, + scst_dlm_post_bast); + if (res < 0) + goto release_lockspace; + + snprintf(lock_name, sizeof(lock_name), PR_PRE_UPDATE_LOCK, + pr_dlm->local_nodeid); + pr_dlm->pre_upd_lksb.pr_dlm = pr_dlm; + res = scst_dlm_lock_wait(ls, DLM_LOCK_EX, &pr_dlm->pre_upd_lksb, + 0, lock_name, scst_dlm_pre_bast); + if (res < 0) + goto release_lockspace; + + switch (lvb->version) { + case 0: + scst_copy_to_dlm(dev, ls); + break; + case 1: + res = scst_copy_from_dlm(dev, ls, &modified_lvb); + break; + default: + PRINT_ERROR("%s: Wrong PR LVB version %d", dev->virt_name, + lvb->version); + goto release_lockspace; + } + + scst_dlm_lock_wait(ls, DLM_LOCK_CR, &pr_dlm->data_lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, PR_DATA_LOCK, + NULL); + + if (res == -EINVAL) + scst_trigger_lvb_update(pr_dlm, ls); + else if (modified_lvb) + scst_trigger_reread_lvb(pr_dlm, ls); + + scst_dlm_unlock_wait(ls, &pr_lksb); + + /* + * Only store the lockspace pointer in pr_dlm->ls after the lockspace + * has been fully initialized. Storing it earlier would create a risk + * that a concurrent get_lockspace() call returns a pointer to the + * lockspace that is under creation. + */ + pr_dlm->ls = ls; + +out_unlock_ls: + mutex_unlock(&pr_dlm->ls_mutex); + +out_unlock_ls_cr: + mutex_unlock(&pr_dlm->ls_cr_mutex); + +out: + return pr_dlm->ls; + +release_lockspace: + scst_dlm_remove_locks(pr_dlm, ls); +unlock_dlm_pr: + scst_dlm_remove_lock(ls, &pr_lksb, PR_LOCK); + mutex_unlock(&pr_dlm->ls_mutex); + + cancel_work_sync(&pr_dlm->copy_from_dlm_work); + cancel_work_sync(&pr_dlm->copy_to_dlm_work); + cancel_work_sync(&pr_dlm->lvb_upd_work); + cancel_work_sync(&pr_dlm->reread_lvb_work); + + release_lockspace(ls, pr_dlm->cl_dev_id); + goto out_unlock_ls_cr; +} + +static bool scst_dlm_pr_is_set(struct scst_device *dev) +{ + get_lockspace(dev); + return dev->pr_is_set; +} + +static void scst_dlm_pr_write_lock(struct scst_device *dev, + struct scst_lksb *pr_lksb) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + dlm_lockspace_t *ls; + + memset(pr_lksb, 0, sizeof(*pr_lksb)); + + ls = get_lockspace(dev); + if (!ls) + goto out; + + scst_dlm_lock_wait(ls, DLM_LOCK_EX, pr_lksb, 0, PR_LOCK, NULL); + if (pr_lksb->lksb.sb_lkid) { + scst_pr_toggle_lock(pr_dlm, ls, PR_POST_UPDATE_LOCK); + scst_pr_toggle_lock(pr_dlm, ls, PR_PRE_UPDATE_LOCK); + scst_dlm_lock_wait(ls, DLM_LOCK_PW, + &pr_dlm->data_lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, + PR_DATA_LOCK, NULL); + } + +out: + /* + * Note: invoking scst_copy_from_dlm(dev) here is not necessary + * because that function is already invoked after joining the + * lockspace and from inside post_bast(). + */ + scst_pr_write_lock(dev); +} + +static void scst_dlm_pr_write_unlock(struct scst_device *dev, + struct scst_lksb *pr_lksb) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + dlm_lockspace_t *ls = pr_dlm->ls; + + scst_pr_write_unlock(dev); + + if (!pr_lksb->lksb.sb_lkid) + return; + + scst_copy_to_dlm(dev, ls); + scst_dlm_lock_wait(ls, DLM_LOCK_CR, &pr_dlm->data_lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, PR_DATA_LOCK, + NULL); + scst_pr_toggle_lock(pr_dlm, ls, PR_POST_UPDATE_LOCK); + scst_dlm_unlock_wait(ls, pr_lksb); +} + +static bool scst_dlm_reserved(struct scst_device *dev) +{ + EXTRACHECKS_BUG_ON(in_irq() || irqs_disabled()); + + get_lockspace(dev); + return dev->reserved_by || dev->pr_dlm->reserved_by_nodeid; +} + +static void scst_dlm_res_lock(struct scst_device *dev, + struct scst_lksb *pr_lksb) + __acquires(&dev->dev_lock) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + dlm_lockspace_t *ls; + + EXTRACHECKS_BUG_ON(in_irq() || irqs_disabled()); + memset(pr_lksb, 0, sizeof(*pr_lksb)); + ls = get_lockspace(dev); + if (!ls) + goto out; + + scst_dlm_lock_wait(ls, DLM_LOCK_EX, pr_lksb, 0, PR_LOCK, NULL); + if (pr_lksb->lksb.sb_lkid) { + scst_dlm_lock_wait(ls, DLM_LOCK_PW, &pr_dlm->data_lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, + PR_DATA_LOCK, NULL); + } + +out: + spin_lock_bh(&dev->dev_lock); +} + +static void scst_dlm_res_unlock(struct scst_device *dev, + struct scst_lksb *pr_lksb) + __releases(&dev->dev_lock) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + dlm_lockspace_t *ls = pr_dlm->ls; + struct pr_lvb *lvb = (void *)pr_dlm->lvb; + bool update_lvb; + + spin_unlock_bh(&dev->dev_lock); + + if (!pr_lksb->lksb.sb_lkid) + return; + + update_lvb = (be32_to_cpu(lvb->reserved_by_nodeid) != + pr_dlm->reserved_by_nodeid); + + if (update_lvb) + scst_copy_to_dlm(dev, ls); + scst_dlm_lock_wait(ls, DLM_LOCK_CR, &pr_dlm->data_lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, PR_DATA_LOCK, + NULL); + if (update_lvb) { + scst_pr_toggle_lock(pr_dlm, ls, PR_PRE_UPDATE_LOCK); + scst_pr_toggle_lock(pr_dlm, ls, PR_POST_UPDATE_LOCK); + } + scst_dlm_unlock_wait(ls, pr_lksb); +} + +static bool scst_dlm_is_rsv_holder(struct scst_device *dev, + struct scst_session *sess) +{ + return dev->reserved_by == sess; +} + +static bool scst_dlm_is_not_rsv_holder(struct scst_device *dev, + struct scst_session *sess) +{ + return dev->pr_dlm->reserved_by_nodeid && dev->reserved_by != sess; +} + +static void scst_dlm_reserve(struct scst_device *dev, struct scst_session *sess) +{ + dev->reserved_by = sess; + dev->pr_dlm->reserved_by_nodeid = sess ? dev->pr_dlm->local_nodeid : 0; +} + +static void scst_dlm_pre_bast(void *bastarg, int mode) +{ + struct scst_lksb *pre_lksb = bastarg; + struct scst_pr_dlm_data *pr_dlm = pre_lksb->pr_dlm; + const bool join = pre_lksb == &pr_dlm->pre_join_lksb; + + /* An AST must not block, so execute further work asynchronously. */ + if (join) + queue_work(pr_dlm->to_wq, &pr_dlm->pre_join_work); + else + queue_work(pr_dlm->from_wq, &pr_dlm->pre_upd_work); +} + +static void scst_pre_join_work(struct work_struct *work) +{ + struct scst_pr_dlm_data *pr_dlm = container_of(work, + struct scst_pr_dlm_data, pre_join_work); + dlm_lockspace_t *ls; + + mutex_lock(&pr_dlm->ls_mutex); + ls = pr_dlm->ls; + if (ls) { + scst_dlm_lock_wait(ls, DLM_LOCK_EX, &pr_dlm->post_join_lksb, + DLM_LKF_CONVERT, NULL, scst_dlm_post_bast); + scst_dlm_lock_wait(ls, DLM_LOCK_NL, &pr_dlm->pre_join_lksb, + DLM_LKF_CONVERT, NULL, scst_dlm_pre_bast); + } + mutex_unlock(&pr_dlm->ls_mutex); +} + +static void scst_pre_upd_work(struct work_struct *work) +{ + struct scst_pr_dlm_data *pr_dlm = container_of(work, + struct scst_pr_dlm_data, pre_upd_work); + dlm_lockspace_t *ls; + + mutex_lock(&pr_dlm->ls_mutex); + ls = pr_dlm->ls; + if (ls) { + scst_dlm_lock_wait(ls, DLM_LOCK_EX, &pr_dlm->post_upd_lksb, + DLM_LKF_CONVERT, NULL, scst_dlm_post_bast); + scst_dlm_lock_wait(ls, DLM_LOCK_NL, &pr_dlm->pre_upd_lksb, + DLM_LKF_CONVERT, NULL, scst_dlm_pre_bast); + } + mutex_unlock(&pr_dlm->ls_mutex); +} + +static void scst_dlm_post_bast(void *bastarg, int mode) +{ + struct scst_lksb *post_lksb = bastarg; + struct scst_pr_dlm_data *pr_dlm = post_lksb->pr_dlm; + const bool join = post_lksb == &pr_dlm->post_join_lksb; + + /* An AST must not block, so execute further work asynchronously. */ + if (join) + queue_work(pr_dlm->to_wq, &pr_dlm->copy_to_dlm_work); + else + queue_work(pr_dlm->from_wq, &pr_dlm->copy_from_dlm_work); +} + +/* + * Note: the node that has invoked scst_trigger_lvb_update() holds PR_LOCK + * in EX mode and waits until this function has finished. + */ +static void scst_copy_to_dlm_work(struct work_struct *work) +{ + struct scst_pr_dlm_data *pr_dlm = container_of(work, + struct scst_pr_dlm_data, copy_to_dlm_work); + struct scst_device *dev = pr_dlm->dev; + dlm_lockspace_t *ls; + int res; + + PRINT_INFO("Copying PR state to the DLM"); + + mutex_lock(&pr_dlm->ls_mutex); + ls = pr_dlm->ls; + if (!ls) + goto unlock_ls; + scst_dlm_lock_wait(ls, DLM_LOCK_EX, &pr_dlm->pre_join_lksb, + DLM_LKF_CONVERT, NULL, scst_dlm_pre_bast); + res = scst_dlm_lock_wait(ls, DLM_LOCK_PW, &pr_dlm->data_lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, PR_DATA_LOCK, + NULL); + if (res < 0) { + PRINT_WARNING("dlm_lock(%s.%s) returned %d", dev->virt_name, + PR_DATA_LOCK, res); + goto unlock_pr; + } + + /* + * Note: whether or not the PR_DATA_LOCK LVB is valid does not matter + * here since we are going to overwrite it anyway. + */ + if (pr_dlm->data_lksb.lksb.sb_flags & DLM_SBF_VALNOTVALID) + PRINT_INFO("%s.%s LVB not valid\n", dev->virt_name, + PR_DATA_LOCK); + + scst_copy_to_dlm(dev, ls); + scst_dlm_lock_wait(ls, DLM_LOCK_CR, &pr_dlm->data_lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, PR_DATA_LOCK, + NULL); + +unlock_pr: + dlm_lock(ls, DLM_LOCK_NL, &pr_dlm->post_join_lksb.lksb, + DLM_LKF_CONVERT, NULL, 0, 0, scst_dlm_post_ast, + &pr_dlm->post_join_lksb, scst_dlm_post_bast); + + PRINT_INFO("Finished copying PR state to the DLM"); + + scst_dlm_update_nodeids(pr_dlm); + + scst_pr_toggle_lock(pr_dlm, ls, PR_POST_UPDATE_LOCK); + scst_pr_toggle_lock(pr_dlm, ls, PR_PRE_UPDATE_LOCK); + scst_pr_toggle_lock(pr_dlm, ls, PR_POST_UPDATE_LOCK); + +unlock_ls: + mutex_unlock(&pr_dlm->ls_mutex); + + PRINT_INFO("Finished notifying other nodes about the new PR state"); +} + +/* + * Note: the scst_copy_from_dlm() call below runs outside command context. It + * is protected against device removal because scst_pr_dlm_cleanup() is + * invoked before a device is removed and that last function waits until this + * function has finished and additionally prevents new invocations of this + * function. The scst_copy_from_dlm() call below is protected against tgt_dev + * addition or removal (e.g. due to a cable pull) because + * scst_pr_init_tgt_dev() and scst_pr_clear_tgt_dev() in scst_pres.c protect + * these manipulations by locking the PR data structures for writing. + */ +static void scst_copy_from_dlm_work(struct work_struct *work) +{ + struct scst_pr_dlm_data *pr_dlm = container_of(work, + struct scst_pr_dlm_data, copy_from_dlm_work); + struct scst_device *dev = pr_dlm->dev; + dlm_lockspace_t *ls; + int res = -ENOENT; + bool modified_lvb = false; + + mutex_lock(&pr_dlm->ls_mutex); + ls = pr_dlm->ls; + if (!ls) + goto unlock_ls; + scst_dlm_lock_wait(ls, DLM_LOCK_EX, &pr_dlm->pre_upd_lksb, + DLM_LKF_CONVERT, NULL, scst_dlm_pre_bast); + res = scst_dlm_lock_wait(ls, DLM_LOCK_PW, &pr_dlm->data_lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, PR_DATA_LOCK, + NULL); + if (res < 0) { + PRINT_WARNING("dlm_lock(%s.%s) returned %d", dev->virt_name, + PR_DATA_LOCK, res); + goto unlock_pr; + } + if (pr_dlm->data_lksb.lksb.sb_flags & DLM_SBF_VALNOTVALID) { + PRINT_WARNING("%s.%s has an invalid lock value block", + dev->virt_name, PR_DATA_LOCK); + res = -EINVAL; + goto unlock_pr; + } + res = scst_copy_from_dlm(dev, ls, &modified_lvb); + scst_dlm_lock_wait(ls, DLM_LOCK_CR, &pr_dlm->data_lksb, + DLM_LKF_CONVERT | DLM_LKF_VALBLK, PR_DATA_LOCK, + NULL); + +unlock_pr: + dlm_lock(ls, DLM_LOCK_NL, &pr_dlm->post_upd_lksb.lksb, + DLM_LKF_CONVERT, NULL, 0, 0, scst_dlm_post_ast, + &pr_dlm->post_upd_lksb, scst_dlm_post_bast); + + scst_dlm_update_nodeids(pr_dlm); + +unlock_ls: + mutex_unlock(&pr_dlm->ls_mutex); + + if (res == -EINVAL) + queue_work(pr_dlm->upd_wq, &pr_dlm->lvb_upd_work); + else if (modified_lvb) + queue_work(pr_dlm->upd_wq, &pr_dlm->reread_lvb_work); +} + +static void scst_dlm_post_ast(void *astarg) +{ +} + +/* Tell other nodes to refresh their local state from the lock value blocks. */ +static void scst_reread_lvb_work(struct work_struct *work) +{ + struct scst_pr_dlm_data *pr_dlm = container_of(work, + struct scst_pr_dlm_data, reread_lvb_work); + dlm_lockspace_t *ls; + struct scst_lksb pr_lksb; + int res; + + mutex_lock(&pr_dlm->ls_mutex); + ls = pr_dlm->ls; + if (!ls) + goto unlock_ls; + memset(&pr_lksb, 0, sizeof(pr_lksb)); + res = scst_dlm_lock_wait(ls, DLM_LOCK_EX, &pr_lksb, 0, PR_LOCK, + NULL); + if (res >= 0) + scst_trigger_reread_lvb(pr_dlm, ls); + if (pr_lksb.lksb.sb_lkid) + scst_dlm_unlock_wait(ls, &pr_lksb); + +unlock_ls: + mutex_unlock(&pr_dlm->ls_mutex); +} + +/* Tell other nodes to update the DLM lock value blocks. */ +static void scst_lvb_upd_work(struct work_struct *work) +{ + struct scst_pr_dlm_data *pr_dlm = container_of(work, + struct scst_pr_dlm_data, lvb_upd_work); + dlm_lockspace_t *ls; + struct scst_lksb lksb; + int res; + + mutex_lock(&pr_dlm->ls_mutex); + ls = pr_dlm->ls; + if (!ls) + goto unlock_ls; + memset(&lksb, 0, sizeof(lksb)); + res = scst_dlm_lock_wait(ls, DLM_LOCK_EX, &lksb, 0, PR_LOCK, NULL); + if (res >= 0) + scst_trigger_lvb_update(pr_dlm, ls); + if (lksb.lksb.sb_lkid) + scst_dlm_unlock_wait(ls, &lksb); + +unlock_ls: + mutex_unlock(&pr_dlm->ls_mutex); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) +static struct workqueue_struct * +alloc_workqueue_backport(const char *fmt, unsigned flags, unsigned max_active, + ...) +{ + struct workqueue_struct *wq = NULL; + va_list ap; + char *name; + + va_start(ap, fmt); + name = kvasprintf(GFP_KERNEL, fmt, ap); + va_end(ap); + if (name) + wq = alloc_workqueue(name, flags, max_active); + kfree(name); + return wq; +} +#undef alloc_workqueue +#define alloc_workqueue alloc_workqueue_backport +#endif + +/* + * Caller must ensure that no commands are being executed for device @dev, + * e.g. by suspending commands before calling this function. + */ +static int scst_pr_dlm_init(struct scst_device *dev, const char *cl_dev_id) +{ + int res = -ENOMEM; + + compile_time_size_checks(); + dev->pr_dlm = kzalloc(sizeof(*dev->pr_dlm), GFP_KERNEL); + if (!dev->pr_dlm) + goto out; + dev->pr_dlm->dev = dev; + mutex_init(&dev->pr_dlm->ls_cr_mutex); + mutex_init(&dev->pr_dlm->ls_mutex); + dev->pr_dlm->data_lksb.lksb.sb_lvbptr = dev->pr_dlm->lvb; + INIT_WORK(&dev->pr_dlm->pre_join_work, scst_pre_join_work); + INIT_WORK(&dev->pr_dlm->pre_upd_work, scst_pre_upd_work); + INIT_WORK(&dev->pr_dlm->copy_from_dlm_work, scst_copy_from_dlm_work); + INIT_WORK(&dev->pr_dlm->copy_to_dlm_work, scst_copy_to_dlm_work); + INIT_WORK(&dev->pr_dlm->lvb_upd_work, scst_lvb_upd_work); + INIT_WORK(&dev->pr_dlm->reread_lvb_work, scst_reread_lvb_work); + dev->pr_dlm->latest_lscr_attempt = jiffies - 100 * HZ; + + res = -ENOMEM; + dev->pr_dlm->cl_dev_id = kstrdup(cl_dev_id, GFP_KERNEL); + if (!dev->pr_dlm->cl_dev_id) + goto err_free; + + dev->pr_dlm->from_wq = alloc_ordered_workqueue("%s_from_dlm", 0, + dev->virt_name); + if (IS_ERR(dev->pr_dlm->from_wq)) { + res = PTR_ERR(dev->pr_dlm->from_wq); + dev->pr_dlm->from_wq = NULL; + goto err_free; + } + + dev->pr_dlm->to_wq = alloc_ordered_workqueue("%s_to_dlm", 0, + dev->virt_name); + if (IS_ERR(dev->pr_dlm->to_wq)) { + res = PTR_ERR(dev->pr_dlm->to_wq); + dev->pr_dlm->to_wq = NULL; + goto err_free; + } + + dev->pr_dlm->upd_wq = alloc_ordered_workqueue("%s_upd_dlm", 0, + dev->virt_name); + if (IS_ERR(dev->pr_dlm->upd_wq)) { + res = PTR_ERR(dev->pr_dlm->upd_wq); + dev->pr_dlm->upd_wq = NULL; + goto err_free; + } + + res = 0; + +out: + return res; + +err_free: + scst_pr_dlm_cleanup(dev); + goto out; +} + +/* + * Note: The caller must ensure that get_lockspace() is not invoked + * concurrently with scst_pr_dlm_cleanup(). This can be realized by suspending + * command execution and by holding scst_mutex. The get_lockspace() callers are: + * - scst_dlm_pr_is_set(); + * - scst_dlm_pr_write_lock(); + * - scst_dlm_reserved(); + * - scst_dlm_res_lock(). + * The first three functions are invoked from command context only. The last + * function is either invoked from command context or is invoked with + * scst_mutex held (from scst_clear_reservation(), + * scst_reassign_persistent_sess_states() and scst_obtain_device_parameters()). + */ +static void scst_pr_dlm_cleanup(struct scst_device *dev) +{ + struct scst_pr_dlm_data *const pr_dlm = dev->pr_dlm; + dlm_lockspace_t *ls; + struct scst_lksb pr_lksb; + + if (!pr_dlm) + return; + ls = pr_dlm->ls; + if (ls) { + memset(&pr_lksb, 0, sizeof(pr_lksb)); + + mutex_lock(&pr_dlm->ls_mutex); + scst_dlm_lock_wait(ls, DLM_LOCK_EX, &pr_lksb, 0, PR_LOCK, NULL); + scst_dlm_remove_locks(pr_dlm, ls); + scst_dlm_unlock_wait(ls, &pr_lksb); + pr_dlm->ls = NULL; + mutex_unlock(&pr_dlm->ls_mutex); + + if (pr_dlm->from_wq) + cancel_work_sync(&pr_dlm->copy_from_dlm_work); + if (pr_dlm->to_wq) + cancel_work_sync(&pr_dlm->copy_to_dlm_work); + if (pr_dlm->upd_wq) { + cancel_work_sync(&pr_dlm->lvb_upd_work); + cancel_work_sync(&pr_dlm->reread_lvb_work); + } + release_lockspace(ls, pr_dlm->cl_dev_id); + } + if (pr_dlm->upd_wq) + destroy_workqueue(pr_dlm->upd_wq); + if (pr_dlm->to_wq) + destroy_workqueue(pr_dlm->to_wq); + if (pr_dlm->from_wq) + destroy_workqueue(pr_dlm->from_wq); + kfree(pr_dlm->nodeid); + kfree(pr_dlm->cl_dev_id); + kfree(pr_dlm); + dev->pr_dlm = NULL; +} + +const struct scst_cl_ops scst_dlm_cl_ops = { + .pr_init = scst_pr_dlm_init, + .pr_cleanup = scst_pr_dlm_cleanup, + .pr_is_set = scst_dlm_pr_is_set, + .pr_init_reg = scst_dlm_pr_init_reg, + .pr_rm_reg = scst_dlm_pr_rm_reg, + .pr_write_lock = scst_dlm_pr_write_lock, + .pr_write_unlock = scst_dlm_pr_write_unlock, + .reserved = scst_dlm_reserved, + .res_lock = scst_dlm_res_lock, + .res_unlock = scst_dlm_res_unlock, + .is_rsv_holder = scst_dlm_is_rsv_holder, + .is_not_rsv_holder = scst_dlm_is_not_rsv_holder, + .reserve = scst_dlm_reserve, +}; diff --git a/scst/src/scst_dlm.h b/scst/src/scst_dlm.h new file mode 100644 index 000000000..0e0956060 --- /dev/null +++ b/scst/src/scst_dlm.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2013 - 2014 Fusion-io, Inc. All rights reserved. + * Copyright (C) 2014 - 2015 SanDisk Corporation. + * + * Synchronization of persistent registration data with DLM lock value blocks. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SCST_PRES_DLM_H +#define __SCST_PRES_DLM_H + +#include +#include +#include + +#define SCST_DLM_LOCKSPACE_PFX "scst-" + +/* + * DLM lock names + */ +#define PR_LOCK "pr" +#define PR_DATA_LOCK "pr_data" +#define PR_PRE_JOIN_LOCK "pr_pre_join_%d" +#define PR_POST_JOIN_LOCK "pr_post_join_%d" +#define PR_PRE_UPDATE_LOCK "pr_pre_%d" +#define PR_POST_UPDATE_LOCK "pr_post_%d" +#define PR_REG_LOCK "pr_reg_%02d" + +/* + * Data members needed for managing PR data via the DLM. + * + * Lock order when using the DLM (from outer to inner): + * - scst_mutex; + * - ls_cr_mutex; + * - ls_mutex; + * - PR_LOCK; + * - PR_PRE_UPDATE_LOCK, PR_POST_UPDATE_LOCK, PR_PRE_JOIN_LOCK, + * PR_POST_JOIN_LOCK; + * - PR_DATA_LOCK; + * - PR_REG_LOCK; + * - dev_pr_mutex / dev_lock. + */ +struct scst_pr_dlm_data { + /* Backpointer to the SCST device. */ + struct scst_device *dev; + + /* Lockspace name suffix. */ + const char *cl_dev_id; + + /* Mutex that protects initialization of the lockspace pointer. */ + struct mutex ls_cr_mutex; + + /* Mutex that protects the lock status blocks. */ + struct mutex ls_mutex; + + /* + * Pointer to the DLM lockspace that contains the persistent + * reservation and SPC-2 reservation data for device @dev. + */ + dlm_lockspace_t *ls; + + /* Time of the latest lockspace creation attempt. */ + unsigned long latest_lscr_attempt; + + /* Corosync node ID of the local node. */ + uint32_t local_nodeid; + + /* Number of elements in the nodeid array. */ + int participants; + + /* Corosync cluster node ID's. Protected by ls_mutex. */ + uint32_t *nodeid; + + /* Workqueue for copy_from_dlm_work. */ + struct workqueue_struct *from_wq; + /* Workqueue for copy_to_dlm_work. */ + struct workqueue_struct *to_wq; + /* Workqueue for lvb_upd_work. */ + struct workqueue_struct *upd_wq; + + struct work_struct pre_join_work; + struct work_struct pre_upd_work; + struct work_struct copy_from_dlm_work; + struct work_struct copy_to_dlm_work; + struct work_struct lvb_upd_work; + struct work_struct reread_lvb_work; + + /* + * DLM lock IDs of the locks used for persistent reservation data and + * the associated notification protocol. + */ + struct scst_lksb pre_join_lksb; + struct scst_lksb post_join_lksb; + struct scst_lksb data_lksb; + struct scst_lksb pre_upd_lksb; + struct scst_lksb post_upd_lksb; + + /* PR_DATA_LOCK LVB. */ + uint8_t lvb[PR_DLM_LVB_LEN]; + + /* SPC-2 reservation state information. */ + uint32_t reserved_by_nodeid; +}; + +/** + * struct pr_lvb - PR_DATA_LOCK LVB data format + * @nr_registrants: number of reservation keys that have been registered + * @pr_generation: persistent reservation generation + * @version: version of this structure + * @pr_is_set: whether the device has been reserved persistently + * @pr_type: persistent reservation type + * @pr_scope: persistent reservation scope + * @pr_aptpl: persistent reservation APTPL + * @reserved_by_nodeid: Corosync node ID of the node holding an SPC-2 + * reservation. Zero if no SPC-2 reservation is held. + */ +struct pr_lvb { + __be32 nr_registrants; + __be32 pr_generation; + u8 version; + u8 pr_is_set; + u8 pr_type; + u8 pr_scope; + u8 pr_aptpl; + u8 reserved[3]; + __be32 reserved_by_nodeid; +}; + +/** + * struct pr_reg_lvb - PR_REG_LOCK LVB data format + * @key: reservation key + * @rel_tgt_id: relative target id + * @version: version of this structure + * @is_holder: whether or not holding the reservation + * @tid: transport ID - up to 228 bytes for iSCSI + */ +struct pr_reg_lvb { + __be64 key; + __be16 rel_tgt_id; + u8 version; + u8 is_holder; + u8 tid[228]; +}; + +#endif /* __SCST_PRES_DLM_H */ diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 9f7118c73..f9f8139d5 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -6090,17 +6090,18 @@ out: static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev) { struct scst_device *dev = tgt_dev->dev; + struct scst_lksb pr_lksb; int release = 0; TRACE_ENTRY(); - spin_lock_bh(&dev->dev_lock); + scst_res_lock(dev, &pr_lksb); if (scst_is_reservation_holder(dev, tgt_dev->sess)) { /* This is one who holds the reservation */ scst_clear_dev_reservation(dev); release = 1; } - spin_unlock_bh(&dev->dev_lock); + scst_res_unlock(dev, &pr_lksb); if (release) scst_send_release(dev); @@ -11729,11 +11730,12 @@ static bool __scst_dev_check_set_UA(struct scst_device *dev, void scst_dev_check_set_UA(struct scst_device *dev, struct scst_cmd *exclude, const uint8_t *sense, int sense_len) { + struct scst_lksb lksb; bool rc; - spin_lock_bh(&dev->dev_lock); + scst_res_lock(dev, &lksb); rc = __scst_dev_check_set_UA(dev, exclude, sense, sense_len); - spin_unlock_bh(&dev->dev_lock); + scst_res_unlock(dev, &lksb); if (rc) scst_unblock_aborted_cmds(NULL, NULL, dev, false); @@ -12480,6 +12482,7 @@ void scst_reassign_retained_sess_states(struct scst_session *new_sess, list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { struct scst_tgt_dev *tgt_dev; struct scst_tgt_dev *new_tgt_dev = NULL, *old_tgt_dev = NULL; + struct scst_lksb pr_lksb; TRACE_DBG("Processing dev %s", dev->virt_name); @@ -12506,11 +12509,13 @@ void scst_reassign_retained_sess_states(struct scst_session *new_sess, /** Reassign regular reservations **/ + scst_res_lock(dev, &pr_lksb); if (scst_is_reservation_holder(dev, old_sess)) { scst_reserve_dev(dev, new_sess); TRACE_DBG("Reservation reassigned from old_tgt_dev %p " "to new_tgt_dev %p", old_tgt_dev, new_tgt_dev); } + scst_res_unlock(dev, &pr_lksb); /** Reassign PRs **/ diff --git a/scst/src/scst_no_dlm.c b/scst/src/scst_no_dlm.c new file mode 100644 index 000000000..2c6d639d4 --- /dev/null +++ b/scst/src/scst_no_dlm.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013 - 2014 Fusion-io, Inc. All rights reserved. + * Copyright (C) 2014 - 2015 SanDisk Corporation. + * + * Synchronization framework of persistent registration data without DLM lock. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifdef INSIDE_KERNEL_TREE +#include +#include +#else +#include "scst.h" +#include "scst_const.h" +#endif +#include "scst_priv.h" +#include "scst_pres.h" + +static int scst_no_dlm_pr_init(struct scst_device *dev, const char *cl_dev_id) +{ + return 0; +} + +static void scst_no_dlm_pr_cleanup(struct scst_device *dev) +{ +} + +static bool scst_no_dlm_pr_is_set(struct scst_device *dev) +{ + return dev->pr_is_set; +} + +static void scst_no_dlm_pr_init_reg(struct scst_device *dev, + struct scst_dev_registrant *reg) +{ +} + +static void scst_no_dlm_pr_rm_reg(struct scst_device *dev, + struct scst_dev_registrant *reg) +{ +} + +static void scst_no_dlm_pr_write_lock(struct scst_device *dev, + struct scst_lksb *pr_lksb) +{ + scst_pr_write_lock(dev); +} + +static void scst_no_dlm_pr_write_unlock(struct scst_device *dev, + struct scst_lksb *pr_lksb) +{ + scst_pr_write_unlock(dev); +} + +static bool scst_no_dlm_reserved(struct scst_device *dev) +{ + return dev->reserved_by; +} + +static void scst_no_dlm_res_lock(struct scst_device *dev, + struct scst_lksb *pr_lksb) + __acquires(&dev->dev_lock) +{ + EXTRACHECKS_BUG_ON(in_irq() || irqs_disabled()); + spin_lock_bh(&dev->dev_lock); +} + +static void scst_no_dlm_res_unlock(struct scst_device *dev, + struct scst_lksb *pr_lksb) + __releases(&dev->dev_lock) +{ + spin_unlock_bh(&dev->dev_lock); +} + +static bool scst_no_dlm_is_rsv_holder(struct scst_device *dev, + struct scst_session *sess) +{ + EXTRACHECKS_BUG_ON(sess == NULL); + return dev->reserved_by == sess; +} + +static bool scst_no_dlm_is_not_rsv_holder(struct scst_device *dev, + struct scst_session *sess) +{ + EXTRACHECKS_BUG_ON(sess == NULL); + return dev->reserved_by && dev->reserved_by != sess; +} + +static void scst_no_dlm_reserve(struct scst_device *dev, + struct scst_session *sess) +{ + dev->reserved_by = sess; +} + +const struct scst_cl_ops scst_no_dlm_cl_ops = { + .pr_init = scst_no_dlm_pr_init, + .pr_cleanup = scst_no_dlm_pr_cleanup, + .pr_is_set = scst_no_dlm_pr_is_set, + .pr_init_reg = scst_no_dlm_pr_init_reg, + .pr_rm_reg = scst_no_dlm_pr_rm_reg, + .pr_write_lock = scst_no_dlm_pr_write_lock, + .pr_write_unlock = scst_no_dlm_pr_write_unlock, + .reserved = scst_no_dlm_reserved, + .res_lock = scst_no_dlm_res_lock, + .res_unlock = scst_no_dlm_res_unlock, + .is_rsv_holder = scst_no_dlm_is_rsv_holder, + .is_not_rsv_holder = scst_no_dlm_is_not_rsv_holder, + .reserve = scst_no_dlm_reserve, +}; diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index 6e6fcad9d..acc04481d 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -88,7 +88,7 @@ static inline void scst_assert_pr_mutex_held(struct scst_device *dev) } #endif -static inline int scst_tid_size(const uint8_t *tid) +int scst_tid_size(const uint8_t *tid) { sBUG_ON(tid == NULL); @@ -185,7 +185,7 @@ out_error: } /* Must be called under dev_pr_mutex */ -static inline void scst_pr_set_holder(struct scst_device *dev, +void scst_pr_set_holder(struct scst_device *dev, struct scst_dev_registrant *holder, uint8_t scope, uint8_t type) { scst_assert_pr_mutex_held(dev); @@ -336,7 +336,7 @@ static void scst_pr_find_registrants_list_key(struct scst_device *dev, } /* dev_pr_mutex must be locked */ -static struct scst_dev_registrant *scst_pr_find_reg( +struct scst_dev_registrant *scst_pr_find_reg( struct scst_device *dev, const uint8_t *transport_id, const uint16_t rel_tgt_id) { @@ -379,7 +379,7 @@ static void scst_pr_clear_reservation(struct scst_device *dev) } /* Must be called under dev_pr_mutex */ -static void scst_pr_clear_holder(struct scst_device *dev) +void scst_pr_clear_holder(struct scst_device *dev) { TRACE_ENTRY(); @@ -401,7 +401,7 @@ static void scst_pr_clear_holder(struct scst_device *dev) } /* Must be called under dev_pr_mutex */ -static struct scst_dev_registrant *scst_pr_add_registrant( +struct scst_dev_registrant *scst_pr_add_registrant( struct scst_device *dev, const uint8_t *transport_id, const uint16_t rel_tgt_id, __be64 key, bool dev_lock_locked) @@ -441,6 +441,8 @@ static struct scst_dev_registrant *scst_pr_add_registrant( goto out; } + dev->cl_ops->pr_init_reg(dev, reg); + reg->transport_id = kmemdup(transport_id, scst_tid_size(transport_id), gfp_flags); if (reg->transport_id == NULL) { @@ -496,7 +498,7 @@ out_free: } /* Must be called under dev_pr_mutex */ -static void scst_pr_remove_registrant(struct scst_device *dev, +void scst_pr_remove_registrant(struct scst_device *dev, struct scst_dev_registrant *reg) { TRACE_ENTRY(); @@ -510,6 +512,8 @@ static void scst_pr_remove_registrant(struct scst_device *dev, list_del(®->dev_registrants_list_entry); + dev->cl_ops->pr_rm_reg(dev, reg); + if (scst_pr_is_holder(dev, reg)) scst_pr_clear_holder(dev); @@ -1142,6 +1146,7 @@ out: int scst_pr_init(struct scst_device *dev) { mutex_init(&dev->dev_pr_mutex); + dev->cl_ops = &scst_no_dlm_cl_ops; dev->pr_generation = 0; dev->pr_is_set = 0; dev->pr_holder = NULL; @@ -1155,8 +1160,41 @@ int scst_pr_init(struct scst_device *dev) /* Free the resources allocated by scst_pr_init(). */ void scst_pr_cleanup(struct scst_device *dev) { + dev->cl_ops->pr_cleanup(dev); } +/* Caller must hold scst_mutex and activity must be suspended. */ +int scst_pr_set_cluster_mode(struct scst_device *dev, bool cluster_mode, + const char *cl_dev_id) +{ + bool cluster_mode_enabled = false; + int res = 0; + +#if defined(CONFIG_DLM) || defined(CONFIG_DLM_MODULE) + cluster_mode_enabled = dev->cl_ops == &scst_dlm_cl_ops; + + if (cluster_mode_enabled == cluster_mode) + goto out; + + PRINT_INFO("%s: changing cluster_mode from %d into %d", dev->virt_name, + cluster_mode_enabled, cluster_mode); + dev->cl_ops->pr_cleanup(dev); + dev->cl_ops = cluster_mode ? &scst_dlm_cl_ops : &scst_no_dlm_cl_ops; + res = dev->cl_ops->pr_init(dev, cl_dev_id); + if (res) { + PRINT_ERROR("%s: changing cluster_mode into %d failed: %d", + dev->virt_name, cluster_mode, res); + dev->cl_ops = &scst_no_dlm_cl_ops; + } +#else + res = cluster_mode ? -ENOTSUPP : 0; +#endif + +out: + return res; +} +EXPORT_SYMBOL(scst_pr_set_cluster_mode); + /* Must be called under dev_pr_mutex or before dev is on the device list. */ int scst_pr_init_dev(struct scst_device *dev) { diff --git a/scst/src/scst_pres.h b/scst/src/scst_pres.h index 3cbecacc5..2decf5b4c 100644 --- a/scst/src/scst_pres.h +++ b/scst/src/scst_pres.h @@ -79,6 +79,11 @@ static inline void scst_pr_read_unlock(struct scst_device *dev) mutex_unlock(&dev->dev_pr_mutex); } +static inline void lockdep_assert_pr_read_lock_held(struct scst_device *dev) +{ + lockdep_assert_held(&dev->dev_pr_mutex); +} + static inline void scst_pr_write_lock(struct scst_device *dev) { mutex_lock(&dev->dev_pr_mutex); @@ -89,6 +94,11 @@ static inline void scst_pr_write_unlock(struct scst_device *dev) mutex_unlock(&dev->dev_pr_mutex); } +static inline void lockdep_assert_pr_write_lock_held(struct scst_device *dev) +{ + lockdep_assert_held(&dev->dev_pr_mutex); +} + int scst_pr_set_file_name(struct scst_device *dev, char **prev, const char *fmt, ...) __printf(3, 4); @@ -120,6 +130,21 @@ void scst_pr_report_caps(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) void scst_pr_read_full_status(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size); +int scst_tid_size(const uint8_t *tid); +struct scst_dev_registrant *scst_pr_find_reg(struct scst_device *dev, + const uint8_t *transport_id, const uint16_t rel_tgt_id); +struct scst_dev_registrant *scst_pr_add_registrant(struct scst_device *dev, + const uint8_t *transport_id, + const uint16_t rel_tgt_id, + __be64 key, + bool dev_lock_locked); +void scst_pr_remove_registrant(struct scst_device *dev, + struct scst_dev_registrant *reg); +void scst_pr_set_holder(struct scst_device *dev, + struct scst_dev_registrant *holder, uint8_t scope, + uint8_t type); +void scst_pr_clear_holder(struct scst_device *dev); + #ifndef CONFIG_SCST_PROC void scst_pr_sync_device_file(struct scst_tgt_dev *tgt_dev, struct scst_cmd *cmd); #endif diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 33056bd41..7d4ef5b33 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -170,6 +170,9 @@ extern struct list_head scst_dev_type_list; extern struct list_head scst_virtual_dev_type_list; extern wait_queue_head_t scst_dev_cmd_waitQ; +extern const struct scst_cl_ops scst_no_dlm_cl_ops; +extern const struct scst_cl_ops scst_dlm_cl_ops; + #ifdef CONFIG_SCST_PROC extern struct list_head scst_acg_list; extern struct scst_acg *scst_default_acg; @@ -398,6 +401,19 @@ void scst_free_session_callback(struct scst_session *sess); void scst_check_retries(struct scst_tgt *tgt); +static inline int scst_dlm_new_lockspace(const char *name, int namelen, + dlm_lockspace_t **lockspace, + uint32_t flags, + int lvblen) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) + return dlm_new_lockspace(name, namelen, lockspace, flags, lvblen); +#else + return dlm_new_lockspace(name, NULL, flags, lvblen, NULL, NULL, NULL, + lockspace); +#endif +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) static inline int scst_exec_req(struct scsi_device *sdev, const unsigned char *cmd, int cmd_len, int data_direction, @@ -599,7 +615,23 @@ void scst_acn_sysfs_del(struct scst_acn *acn); */ static inline bool scst_dev_reserved(struct scst_device *dev) { - return dev->reserved_by; + return dev->cl_ops->reserved(dev); +} + + +/* Protect SPC-2 reservation state against concurrent modifications. */ +static inline void scst_res_lock(struct scst_device *dev, + struct scst_lksb *pr_lksb) + __acquires(&dev->dev_lock) +{ + dev->cl_ops->res_lock(dev, pr_lksb); +} + +static inline void scst_res_unlock(struct scst_device *dev, + struct scst_lksb *pr_lksb) + __releases(&dev->dev_lock) +{ + dev->cl_ops->res_unlock(dev, pr_lksb); } /* @@ -610,7 +642,7 @@ static inline bool scst_is_reservation_holder(struct scst_device *dev, struct scst_session *sess) { EXTRACHECKS_BUG_ON(sess == NULL); - return dev->reserved_by == sess; + return dev->cl_ops->is_rsv_holder(dev, sess); } /* @@ -620,23 +652,22 @@ static inline bool scst_is_reservation_holder(struct scst_device *dev, static inline bool scst_is_not_reservation_holder(struct scst_device *dev, struct scst_session *sess) { - struct scst_session *reserved_by = dev->reserved_by; - EXTRACHECKS_BUG_ON(sess == NULL); - return reserved_by != NULL && reserved_by != sess; + return dev->cl_ops->is_not_rsv_holder(dev, sess); } static inline void scst_reserve_dev(struct scst_device *dev, struct scst_session *sess) { + lockdep_assert_held(&dev->dev_lock); EXTRACHECKS_BUG_ON(sess == NULL); - dev->reserved_by = sess; + dev->cl_ops->reserve(dev, sess); } static inline void scst_clear_dev_reservation(struct scst_device *dev) { lockdep_assert_held(&dev->dev_lock); - dev->reserved_by = NULL; + dev->cl_ops->reserve(dev, NULL); } void scst_tgt_dev_del_free_UA(struct scst_tgt_dev *tgt_dev, diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 7a4a033d7..614ba3312 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -3139,12 +3139,16 @@ static ssize_t scst_dev_sysfs_pr_file_name_store(struct kobject *kobj, { struct scst_sysfs_work_item *work; struct scst_device *dev; - char *pr_file_name, *p; - int res = -ENOMEM; + char *pr_file_name = NULL, *p; + int res = -EPERM; bool def = false; dev = container_of(kobj, struct scst_device, dev_kobj); + if (dev->cluster_mode) + goto out; + + res = -ENOMEM; pr_file_name = kasprintf(GFP_KERNEL, "%.*s", (int)count, buf); if (!pr_file_name) { PRINT_ERROR("Unable to kasprintf() PR file name"); diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index d0216b238..44539099b 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -2379,6 +2379,7 @@ static int scst_reserve_local(struct scst_cmd *cmd) { int res = SCST_EXEC_NOT_COMPLETED; struct scst_device *dev; + struct scst_lksb pr_lksb; TRACE_ENTRY(); @@ -2419,14 +2420,14 @@ static int scst_reserve_local(struct scst_cmd *cmd) } } - spin_lock_bh(&dev->dev_lock); + scst_res_lock(dev, &pr_lksb); if (scst_is_not_reservation_holder(dev, cmd->sess)) { - spin_unlock_bh(&dev->dev_lock); + scst_res_unlock(dev, &pr_lksb); scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT); goto out_done; } scst_reserve_dev(dev, cmd->sess); - spin_unlock_bh(&dev->dev_lock); + scst_res_unlock(dev, &pr_lksb); out: TRACE_EXIT_RES(res); @@ -2446,6 +2447,7 @@ static int scst_release_local(struct scst_cmd *cmd) { int res = SCST_EXEC_NOT_COMPLETED; struct scst_device *dev; + struct scst_lksb pr_lksb; TRACE_ENTRY(); @@ -2466,7 +2468,7 @@ static int scst_release_local(struct scst_cmd *cmd) } } - spin_lock_bh(&dev->dev_lock); + scst_res_lock(dev, &pr_lksb); /* * The device could be RELEASED behind us, if RESERVING session @@ -2489,7 +2491,7 @@ static int scst_release_local(struct scst_cmd *cmd) scst_clear_dev_reservation(dev); } - spin_unlock_bh(&dev->dev_lock); + scst_res_unlock(dev, &pr_lksb); if (res == SCST_EXEC_COMPLETED) goto out_done; @@ -2616,6 +2618,7 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) int action; uint8_t *buffer; int buffer_size; + struct scst_lksb pr_lksb; bool aborted = false; TRACE_ENTRY(); @@ -2651,7 +2654,7 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) if (unlikely(buffer_size <= 0)) goto out_done; - scst_pr_write_lock(dev); + dev->cl_ops->pr_write_lock(dev, &pr_lksb); /* * Check if tgt_dev already registered. Also by this check we make @@ -2742,7 +2745,7 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) res = SCST_EXEC_NOT_COMPLETED; out_unlock: - scst_pr_write_unlock(dev); + dev->cl_ops->pr_write_unlock(dev, &pr_lksb); scst_put_buf_full(cmd, buffer); @@ -2816,7 +2819,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only) } if (!preempt_tests_only) { - if (dev->pr_is_set) { + if (dev->cl_ops->pr_is_set(dev)) { if (unlikely(!scst_pr_is_cmd_allowed(cmd))) { scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT); @@ -5980,14 +5983,15 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd) list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) { struct scst_device *d; struct scst_tgt_dev *tgt_dev; + struct scst_lksb pr_lksb; int found = 0; dev = acg_dev->dev; - spin_lock_bh(&dev->dev_lock); + scst_res_lock(dev, &pr_lksb); scst_block_dev(dev); scst_process_reset(dev, mcmd->sess, NULL, mcmd, true); - spin_unlock_bh(&dev->dev_lock); + scst_res_unlock(dev, &pr_lksb); list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { @@ -6076,6 +6080,7 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd) int res, rc; struct scst_tgt_dev *tgt_dev = mcmd->mcmd_tgt_dev; struct scst_device *dev = tgt_dev->dev; + struct scst_lksb pr_lksb; TRACE_ENTRY(); @@ -6084,10 +6089,10 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd) mcmd->needs_unblocking = 1; - spin_lock_bh(&dev->dev_lock); + scst_res_lock(dev, &pr_lksb); scst_block_dev(dev); scst_process_reset(dev, mcmd->sess, NULL, mcmd, true); - spin_unlock_bh(&dev->dev_lock); + scst_res_unlock(dev, &pr_lksb); scst_call_dev_task_mgmt_fn_received(mcmd, tgt_dev);