mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-18 13:16:34 +00:00
scst: implement BLOCKIO devices "active" attribute
Intended to be able to load on passive side as described in https://sourceforge.net/p/scst/mailman/message/35549446/ Suggested-by: Кирилл Тюшев <kirill.tyushev8@gmail.com> git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7187 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+9
-4
@@ -1696,10 +1696,15 @@ DRBD as well as other replication/failover SW does not allow to open its
|
|||||||
device on the secondary as well as does not allow to perform primary to
|
device on the secondary as well as does not allow to perform primary to
|
||||||
secondary transition, if this device is open.
|
secondary transition, if this device is open.
|
||||||
|
|
||||||
SCST BLOCKIO handler has all the necessary support for such behavior. If
|
SCST BLOCKIO handler has necessary support for such behavior:
|
||||||
you write new ALUA state in the "state" attribute, SCST BLOCKIO handler
|
|
||||||
before transition closes the open devices' handles and after transition
|
1. If you need to prevent an SCST BLOCKIO device from opening its block
|
||||||
reopens them, if the new state is active or nonoptimized.
|
device, you need to create it with parameter "active=0"
|
||||||
|
|
||||||
|
2. If you write new ALUA state in the "state" attribute, SCST BLOCKIO
|
||||||
|
handler before transition closes open handles on all affected SCST
|
||||||
|
devices and after transition reopens them, if the new state is active or
|
||||||
|
nonoptimized.
|
||||||
|
|
||||||
Thus, the recommended implicit ALUA state change procedure for primary
|
Thus, the recommended implicit ALUA state change procedure for primary
|
||||||
to secondary transition is:
|
to secondary transition is:
|
||||||
|
|||||||
+9
-4
@@ -1549,10 +1549,15 @@ DRBD as well as other replication/failover SW does not allow to open its
|
|||||||
device on the secondary as well as does not allow to perform primary to
|
device on the secondary as well as does not allow to perform primary to
|
||||||
secondary transition, if this device is open.
|
secondary transition, if this device is open.
|
||||||
|
|
||||||
SCST BLOCKIO handler has all the necessary support for such behavior. If
|
SCST BLOCKIO handler has necessary support for such behavior:
|
||||||
you write new ALUA state in the "state" attribute, SCST BLOCKIO handler
|
|
||||||
before transition closes the open devices' handles and after transition
|
1. If you need to prevent an SCST BLOCKIO device from opening its block
|
||||||
reopens them, if the new state is active or nonoptimized.
|
device, you need to create it with parameter "active=0"
|
||||||
|
|
||||||
|
2. If you write new ALUA state in the "state" attribute, SCST BLOCKIO
|
||||||
|
handler before transition closes open handles on all affected SCST
|
||||||
|
devices and after transition reopens them, if the new state is active or
|
||||||
|
nonoptimized.
|
||||||
|
|
||||||
Thus, the recommended implicit ALUA state change procedure for primary
|
Thus, the recommended implicit ALUA state change procedure for primary
|
||||||
to secondary transition is:
|
to secondary transition is:
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = {
|
|||||||
#define DEF_ROTATIONAL 1
|
#define DEF_ROTATIONAL 1
|
||||||
#define DEF_THIN_PROVISIONED 0
|
#define DEF_THIN_PROVISIONED 0
|
||||||
#define DEF_EXPL_ALUA 0
|
#define DEF_EXPL_ALUA 0
|
||||||
|
#define DEF_DEV_ACTIVE 1
|
||||||
|
|
||||||
#define VDISK_NULLIO_SIZE (5LL*1024*1024*1024*1024/2)
|
#define VDISK_NULLIO_SIZE (5LL*1024*1024*1024*1024/2)
|
||||||
|
|
||||||
@@ -168,6 +169,7 @@ struct scst_vdisk_dev {
|
|||||||
* Below flags are protected by flags_lock or suspended activity
|
* Below flags are protected by flags_lock or suspended activity
|
||||||
* with scst_vdisk_mutex.
|
* with scst_vdisk_mutex.
|
||||||
*/
|
*/
|
||||||
|
unsigned int dev_active:1;
|
||||||
unsigned int rd_only:1;
|
unsigned int rd_only:1;
|
||||||
unsigned int wt_flag:1;
|
unsigned int wt_flag:1;
|
||||||
unsigned int nv_cache:1;
|
unsigned int nv_cache:1;
|
||||||
@@ -418,6 +420,8 @@ static ssize_t vdisk_sysfs_nv_cache_show(struct kobject *kobj,
|
|||||||
struct kobj_attribute *attr, char *buf);
|
struct kobj_attribute *attr, char *buf);
|
||||||
static ssize_t vdisk_sysfs_o_direct_show(struct kobject *kobj,
|
static ssize_t vdisk_sysfs_o_direct_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf);
|
struct kobj_attribute *attr, char *buf);
|
||||||
|
static ssize_t vdev_sysfs_active_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, char *buf);
|
||||||
static ssize_t vdev_sysfs_dummy_show(struct kobject *kobj,
|
static ssize_t vdev_sysfs_dummy_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf);
|
struct kobj_attribute *attr, char *buf);
|
||||||
static ssize_t vdev_sysfs_rz_show(struct kobject *kobj,
|
static ssize_t vdev_sysfs_rz_show(struct kobject *kobj,
|
||||||
@@ -484,6 +488,8 @@ static ssize_t vdev_dif_filename_show(struct kobject *kobj,
|
|||||||
static ssize_t vcdrom_sysfs_filename_store(struct kobject *kobj,
|
static ssize_t vcdrom_sysfs_filename_store(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, const char *buf, size_t count);
|
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||||
|
|
||||||
|
static struct kobj_attribute vdev_active_attr =
|
||||||
|
__ATTR(active, S_IRUGO, vdev_sysfs_active_show, NULL);
|
||||||
static struct kobj_attribute vdev_size_ro_attr =
|
static struct kobj_attribute vdev_size_ro_attr =
|
||||||
__ATTR(size, S_IRUGO, vdev_sysfs_size_show, NULL);
|
__ATTR(size, S_IRUGO, vdev_sysfs_size_show, NULL);
|
||||||
static struct kobj_attribute vdev_size_rw_attr =
|
static struct kobj_attribute vdev_size_rw_attr =
|
||||||
@@ -604,6 +610,7 @@ static const struct attribute *vdisk_fileio_attrs[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct attribute *vdisk_blockio_attrs[] = {
|
static const struct attribute *vdisk_blockio_attrs[] = {
|
||||||
|
&vdev_active_attr.attr,
|
||||||
&vdev_size_rw_attr.attr,
|
&vdev_size_rw_attr.attr,
|
||||||
&vdev_size_mb_rw_attr.attr,
|
&vdev_size_mb_rw_attr.attr,
|
||||||
&vdisk_blocksize_attr.attr,
|
&vdisk_blocksize_attr.attr,
|
||||||
@@ -939,6 +946,12 @@ static struct file *vdev_open_fd(const struct scst_vdisk_dev *virt_dev,
|
|||||||
|
|
||||||
sBUG_ON(!name);
|
sBUG_ON(!name);
|
||||||
|
|
||||||
|
if (!virt_dev->dev_active) {
|
||||||
|
TRACE_MGMT_DBG("Skip openning for not active dev %s", virt_dev->dev->virt_name);
|
||||||
|
fd = ERR_PTR(-EMEDIUMTYPE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (read_only)
|
if (read_only)
|
||||||
open_flags |= O_RDONLY;
|
open_flags |= O_RDONLY;
|
||||||
else
|
else
|
||||||
@@ -958,6 +971,7 @@ static struct file *vdev_open_fd(const struct scst_vdisk_dev *virt_dev,
|
|||||||
PRINT_ERROR("filp_open(%s) failed: %d", name, (int)PTR_ERR(fd));
|
PRINT_ERROR("filp_open(%s) failed: %d", name, (int)PTR_ERR(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
TRACE_EXIT();
|
TRACE_EXIT();
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
@@ -969,7 +983,7 @@ static void vdisk_blockio_check_flush_support(struct scst_vdisk_dev *virt_dev)
|
|||||||
|
|
||||||
TRACE_ENTRY();
|
TRACE_ENTRY();
|
||||||
|
|
||||||
if (!virt_dev->blockio || virt_dev->rd_only || virt_dev->nv_cache || virt_dev->wt_flag)
|
if (!virt_dev->blockio || virt_dev->rd_only || virt_dev->nv_cache || virt_dev->wt_flag || !virt_dev->dev_active)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600);
|
fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600);
|
||||||
@@ -1014,7 +1028,7 @@ static void vdisk_check_tp_support(struct scst_vdisk_dev *virt_dev)
|
|||||||
|
|
||||||
virt_dev->dev_thin_provisioned = 0;
|
virt_dev->dev_thin_provisioned = 0;
|
||||||
|
|
||||||
if (virt_dev->rd_only || (virt_dev->filename == NULL))
|
if (virt_dev->rd_only || (virt_dev->filename == NULL) || !virt_dev->dev_active)
|
||||||
goto check;
|
goto check;
|
||||||
|
|
||||||
fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600);
|
fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600);
|
||||||
@@ -1126,7 +1140,7 @@ check:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 0 on success and file size in *file_size, error code otherwise */
|
/* Returns 0 on success and file size in *file_size, error code otherwise */
|
||||||
static int vdisk_get_file_size(const char *filename, bool blockio,
|
static int vdisk_get_file_size(const struct scst_vdisk_dev *virt_dev,
|
||||||
loff_t *file_size)
|
loff_t *file_size)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
@@ -1135,25 +1149,31 @@ static int vdisk_get_file_size(const char *filename, bool blockio,
|
|||||||
|
|
||||||
TRACE_ENTRY();
|
TRACE_ENTRY();
|
||||||
|
|
||||||
sBUG_ON(!filename);
|
sBUG_ON(!virt_dev->filename);
|
||||||
|
|
||||||
|
if (!virt_dev->dev_active) {
|
||||||
|
TRACE_DBG("Not active dev %s, skip reexaming", virt_dev->dev->virt_name);
|
||||||
|
res = -EMEDIUMTYPE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
*file_size = 0;
|
*file_size = 0;
|
||||||
|
|
||||||
fd = filp_open(filename, O_LARGEFILE | O_RDONLY, 0600);
|
fd = filp_open(virt_dev->filename, O_LARGEFILE | O_RDONLY, 0600);
|
||||||
if (IS_ERR(fd)) {
|
if (IS_ERR(fd)) {
|
||||||
res = PTR_ERR(fd);
|
res = PTR_ERR(fd);
|
||||||
if ((res == -EMEDIUMTYPE) && blockio)
|
if ((res == -EMEDIUMTYPE) && virt_dev->blockio)
|
||||||
TRACE(TRACE_MINOR, "Unable to open %s with EMEDIUMTYPE, "
|
TRACE(TRACE_MINOR, "Unable to open %s with EMEDIUMTYPE, "
|
||||||
"DRBD passive?", filename);
|
"DRBD passive?", virt_dev->filename);
|
||||||
else
|
else
|
||||||
PRINT_ERROR("filp_open(%s) failed: %d", filename, res);
|
PRINT_ERROR("filp_open(%s) failed: %d", virt_dev->filename, res);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
inode = file_inode(fd);
|
inode = file_inode(fd);
|
||||||
|
|
||||||
if (blockio && !S_ISBLK(inode->i_mode)) {
|
if (virt_dev->blockio && !S_ISBLK(inode->i_mode)) {
|
||||||
PRINT_ERROR("File %s is NOT a block device", filename);
|
PRINT_ERROR("File %s is NOT a block device", virt_dev->filename);
|
||||||
res = -EINVAL;
|
res = -EINVAL;
|
||||||
goto out_close;
|
goto out_close;
|
||||||
}
|
}
|
||||||
@@ -1164,7 +1184,7 @@ static int vdisk_get_file_size(const char *filename, bool blockio,
|
|||||||
inode = inode->i_bdev->bd_inode;
|
inode = inode->i_bdev->bd_inode;
|
||||||
} else {
|
} else {
|
||||||
PRINT_ERROR("File %s unsupported mode: mode=0%o\n",
|
PRINT_ERROR("File %s unsupported mode: mode=0%o\n",
|
||||||
filename, inode->i_mode);
|
virt_dev->filename, inode->i_mode);
|
||||||
res = -EINVAL;
|
res = -EINVAL;
|
||||||
goto out_close;
|
goto out_close;
|
||||||
}
|
}
|
||||||
@@ -1571,8 +1591,7 @@ static int vdisk_reexamine(struct scst_vdisk_dev *virt_dev)
|
|||||||
if (!virt_dev->nullio && !virt_dev->cdrom_empty) {
|
if (!virt_dev->nullio && !virt_dev->cdrom_empty) {
|
||||||
loff_t file_size;
|
loff_t file_size;
|
||||||
|
|
||||||
res = vdisk_get_file_size(virt_dev->filename, virt_dev->blockio,
|
res = vdisk_get_file_size(virt_dev, &file_size);
|
||||||
&file_size);
|
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
if ((res == -EMEDIUMTYPE) && virt_dev->blockio) {
|
if ((res == -EMEDIUMTYPE) && virt_dev->blockio) {
|
||||||
TRACE_DBG("Reexam pending (dev %s)", virt_dev->name);
|
TRACE_DBG("Reexam pending (dev %s)", virt_dev->name);
|
||||||
@@ -7427,9 +7446,11 @@ static void blockio_on_alua_state_change_start(struct scst_device *dev,
|
|||||||
* no parallel fd activities could be here.
|
* no parallel fd activities could be here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TRACE_MGMT_DBG("ALUA state change from %s to %s started, closing FD (dev %s)",
|
TRACE_MGMT_DBG("ALUA state change from %s to %s started, closing FD (dev %s, active %d)",
|
||||||
scst_alua_state_name(old_state), scst_alua_state_name(new_state),
|
scst_alua_state_name(old_state), scst_alua_state_name(new_state),
|
||||||
dev->virt_name);
|
dev->virt_name, virt_dev->dev_active);
|
||||||
|
|
||||||
|
virt_dev->dev_active = 0;
|
||||||
|
|
||||||
/* Just in case always close */
|
/* Just in case always close */
|
||||||
vdisk_close_fd(virt_dev);
|
vdisk_close_fd(virt_dev);
|
||||||
@@ -7455,9 +7476,11 @@ static void blockio_on_alua_state_change_finish(struct scst_device *dev,
|
|||||||
/* Try non-optimized as well, it might be new redirection device */
|
/* Try non-optimized as well, it might be new redirection device */
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
TRACE_MGMT_DBG("ALUA state change from %s to %s finished (dev %s), "
|
TRACE_MGMT_DBG("ALUA state change from %s to %s finished (dev %s, active %d), "
|
||||||
"reopening FD", scst_alua_state_name(old_state),
|
"reopening FD", scst_alua_state_name(old_state),
|
||||||
scst_alua_state_name(new_state), dev->virt_name);
|
scst_alua_state_name(new_state), dev->virt_name, virt_dev->dev_active);
|
||||||
|
|
||||||
|
virt_dev->dev_active = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* only reopen fd if tgt_dev_cnt is not zero, otherwise we will
|
* only reopen fd if tgt_dev_cnt is not zero, otherwise we will
|
||||||
@@ -7640,6 +7663,10 @@ static void vdisk_report_registering(const struct scst_vdisk_dev *virt_dev)
|
|||||||
i += snprintf(&buf[i], buf_size - i, "%sREMOVABLE",
|
i += snprintf(&buf[i], buf_size - i, "%sREMOVABLE",
|
||||||
(j == i) ? "(" : ", ");
|
(j == i) ? "(" : ", ");
|
||||||
|
|
||||||
|
if (!virt_dev->dev_active)
|
||||||
|
i += snprintf(&buf[i], buf_size - i, "%sINACTIVE",
|
||||||
|
(j == i) ? "(" : ", ");
|
||||||
|
|
||||||
if (virt_dev->tst != DEF_TST)
|
if (virt_dev->tst != DEF_TST)
|
||||||
i += snprintf(&buf[i], buf_size - i, "%sTST %d",
|
i += snprintf(&buf[i], buf_size - i, "%sTST %d",
|
||||||
(j == i) ? "(" : ", ", virt_dev->tst);
|
(j == i) ? "(" : ", ", virt_dev->tst);
|
||||||
@@ -7687,13 +7714,12 @@ static int vdisk_resync_size(struct scst_vdisk_dev *virt_dev)
|
|||||||
sBUG_ON(virt_dev->nullio);
|
sBUG_ON(virt_dev->nullio);
|
||||||
sBUG_ON(!virt_dev->filename);
|
sBUG_ON(!virt_dev->filename);
|
||||||
|
|
||||||
if (virt_dev->fd == NULL) {
|
if ((virt_dev->fd == NULL) || !virt_dev->dev_active) {
|
||||||
res = -EMEDIUMTYPE;
|
res = -EMEDIUMTYPE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = vdisk_get_file_size(virt_dev->filename,
|
res = vdisk_get_file_size(virt_dev, &file_size);
|
||||||
virt_dev->blockio, &file_size);
|
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -7829,6 +7855,7 @@ static int vdev_create_node(struct scst_dev_type *devt,
|
|||||||
|
|
||||||
virt_dev->blk_shift = DEF_DISK_BLOCK_SHIFT;
|
virt_dev->blk_shift = DEF_DISK_BLOCK_SHIFT;
|
||||||
virt_dev->numa_node_id = NUMA_NO_NODE;
|
virt_dev->numa_node_id = NUMA_NO_NODE;
|
||||||
|
virt_dev->dev_active = DEF_DEV_ACTIVE;
|
||||||
|
|
||||||
if (strlen(name) >= sizeof(virt_dev->name)) {
|
if (strlen(name) >= sizeof(virt_dev->name)) {
|
||||||
PRINT_ERROR("Name %s is too long (max allowed %zd)", name,
|
PRINT_ERROR("Name %s is too long (max allowed %zd)", name,
|
||||||
@@ -8103,6 +8130,9 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev,
|
|||||||
} else if (!strcasecmp("removable", p)) {
|
} else if (!strcasecmp("removable", p)) {
|
||||||
virt_dev->removable = val;
|
virt_dev->removable = val;
|
||||||
TRACE_DBG("REMOVABLE %d", virt_dev->removable);
|
TRACE_DBG("REMOVABLE %d", virt_dev->removable);
|
||||||
|
} else if (!strcasecmp("active", p)) {
|
||||||
|
virt_dev->dev_active = val;
|
||||||
|
TRACE_DBG("ACTIVE %d", virt_dev->dev_active);
|
||||||
} else if (!strcasecmp("rotational", p)) {
|
} else if (!strcasecmp("rotational", p)) {
|
||||||
virt_dev->rotational = val;
|
virt_dev->rotational = val;
|
||||||
TRACE_DBG("ROTATIONAL %d", virt_dev->rotational);
|
TRACE_DBG("ROTATIONAL %d", virt_dev->rotational);
|
||||||
@@ -8243,7 +8273,7 @@ static int vdev_blockio_add_device(const char *device_name, char *params)
|
|||||||
const char *const allowed_params[] = { "filename", "read_only", "write_through",
|
const char *const allowed_params[] = { "filename", "read_only", "write_through",
|
||||||
"removable", "blocksize", "nv_cache",
|
"removable", "blocksize", "nv_cache",
|
||||||
"rotational", "cluster_mode",
|
"rotational", "cluster_mode",
|
||||||
"thin_provisioned", "tst",
|
"thin_provisioned", "tst", "active",
|
||||||
"numa_node_id", "dif_mode",
|
"numa_node_id", "dif_mode",
|
||||||
"dif_type", "dif_static_app_tag",
|
"dif_type", "dif_static_app_tag",
|
||||||
"dif_filename", NULL };
|
"dif_filename", NULL };
|
||||||
@@ -8649,8 +8679,7 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev,
|
|||||||
|
|
||||||
virt_dev->filename = fn;
|
virt_dev->filename = fn;
|
||||||
|
|
||||||
res = vdisk_get_file_size(virt_dev->filename,
|
res = vdisk_get_file_size(virt_dev, &err);
|
||||||
virt_dev->blockio, &err);
|
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
goto out_free_fn;
|
goto out_free_fn;
|
||||||
if (virt_dev->fd == NULL) {
|
if (virt_dev->fd == NULL) {
|
||||||
@@ -10153,6 +10182,25 @@ static ssize_t vdev_sysfs_inq_vend_specific_show(struct kobject *kobj,
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t vdev_sysfs_active_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
struct scst_device *dev;
|
||||||
|
struct scst_vdisk_dev *virt_dev;
|
||||||
|
|
||||||
|
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||||
|
virt_dev = dev->dh_priv;
|
||||||
|
|
||||||
|
pos = snprintf(buf, PAGE_SIZE, "%d\n%s",
|
||||||
|
virt_dev->dev_active,
|
||||||
|
virt_dev->dev_active != DEF_DEV_ACTIVE ?
|
||||||
|
SCST_SYSFS_KEY_MARK "\n" : "");
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t vdev_zero_copy_show(struct kobject *kobj,
|
static ssize_t vdev_zero_copy_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf)
|
struct kobj_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user