mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-20 06:06:23 +00:00
scst: Rework Copy Manager's sysfs interface
The old version had management incompatible with scstadmin and had issues with LUNs management. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6694 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+8
-17
@@ -1859,34 +1859,25 @@ EXTENDED COPY
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
SCST implements EXTENDED COPY via internal Copy Manager target. This
|
||||
target has the following specific attributes in its sysfs:
|
||||
target has the following specific attribute in its sysfs:
|
||||
|
||||
- allow_not_connected_copy - if not set (default), an initiator can
|
||||
perform copy only between devices it has direct access to via any
|
||||
target/session. If set, any initiator can copy between any devices in
|
||||
the system.
|
||||
|
||||
- mgmt - this attribute allows to control data from which devices can
|
||||
be copied using Copy Manager. By default, devices belonging to dev
|
||||
handlers with flag auto_cm_assignment_possible set are auto assigned to
|
||||
the Copy Manager on the registration. Currently, only vdisk has this
|
||||
flag set, so all other devices (pass-through, user space, etc.) should
|
||||
be assigned to the Copy Manager manually.
|
||||
|
||||
Mgmt attribute supports the following commands:
|
||||
|
||||
- add [vname|H:C:I:L] - adds device with name vname or H:C:I:L numbers
|
||||
(pass-through) to the Copy Manager.
|
||||
|
||||
- del [vname|H:C:I:L] - deletes device with name vname or H:C:I:L numbers
|
||||
(pass-through) from the Copy Manager.
|
||||
|
||||
The Copy Manager has access only to those devices, for which it has LUNs
|
||||
in /sys/kernel/scst_tgt/targets/copy_manager/copy_manager_tgt/luns/.
|
||||
Devices from scst_vdisk dev handler added to it automatically upon
|
||||
registration, but for other devices you need to manually add LUNs there
|
||||
the same way as for any target driver. You can also delete any device at
|
||||
any time from the Copy Manager visibility by deleting the corresponding
|
||||
LUN from the sysfs. It might be useful during ALUA state switching.
|
||||
|
||||
Internally SCST implements EXTENDED COPY as generation of sets of
|
||||
internal READ(16) and WRITE(16) SCSI commands. Dev handlers don't need
|
||||
any manual actions to use it.
|
||||
|
||||
|
||||
Also SCST provides for dev handlers possibility to remap blocks instead
|
||||
of copy them, if they support this feature. It allows them to perform
|
||||
EXTENDED COPY command much faster by just metadata update of their
|
||||
|
||||
+8
-17
@@ -1712,34 +1712,25 @@ EXTENDED COPY
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
SCST implements EXTENDED COPY via internal Copy Manager target. This
|
||||
target has the following specific attributes in its sysfs:
|
||||
target has the following specific attribute in its sysfs:
|
||||
|
||||
- allow_not_connected_copy - if not set (default), an initiator can
|
||||
perform copy only between devices it has direct access to via any
|
||||
target/session. If set, any initiator can copy between any devices in
|
||||
the system.
|
||||
|
||||
- mgmt - this attribute allows to control data from which devices can
|
||||
be copied using Copy Manager. By default, devices belonging to dev
|
||||
handlers with flag auto_cm_assignment_possible set are auto assigned to
|
||||
the Copy Manager on the registration. Currently, only vdisk has this
|
||||
flag set, so all other devices (pass-through, user space, etc.) should
|
||||
be assigned to the Copy Manager manually.
|
||||
|
||||
Mgmt attribute supports the following commands:
|
||||
|
||||
- add [vname|H:C:I:L] - adds device with name vname or H:C:I:L numbers
|
||||
(pass-through) to the Copy Manager.
|
||||
|
||||
- del [vname|H:C:I:L] - deletes device with name vname or H:C:I:L numbers
|
||||
(pass-through) from the Copy Manager.
|
||||
|
||||
The Copy Manager has access only to those devices, for which it has LUNs
|
||||
in /sys/kernel/scst_tgt/targets/copy_manager/copy_manager_tgt/luns/.
|
||||
Devices from scst_vdisk dev handler added to it automatically upon
|
||||
registration, but for other devices you need to manually add LUNs there
|
||||
the same way as for any target driver. You can also delete any device at
|
||||
any time from the Copy Manager visibility by deleting the corresponding
|
||||
LUN from the sysfs. It might be useful during ALUA state switching.
|
||||
|
||||
Internally SCST implements EXTENDED COPY as generation of sets of
|
||||
internal READ(16) and WRITE(16) SCSI commands. Dev handlers don't need
|
||||
any manual actions to use it.
|
||||
|
||||
|
||||
Also SCST provides for dev handlers possibility to remap blocks instead
|
||||
of copy them, if they support this feature. It allows them to perform
|
||||
EXTENDED COPY command much faster by just metadata update of their
|
||||
|
||||
+115
-158
@@ -2519,14 +2519,16 @@ static bool scst_cm_is_lun_free(unsigned int lun)
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held and activities suspended */
|
||||
static int scst_cm_dev_register(struct scst_device *dev)
|
||||
static int scst_cm_dev_register(struct scst_device *dev, uint64_t lun)
|
||||
{
|
||||
int res, i;
|
||||
unsigned int lun;
|
||||
struct scst_acg_dev *acg_dev;
|
||||
bool add_lun;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("dev %s, LUN %ld", dev->virt_name, (unsigned long)lun);
|
||||
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct list_head *head = &scst_cm_sess->sess_tgt_dev_list[i];
|
||||
@@ -2541,18 +2543,25 @@ static int scst_cm_dev_register(struct scst_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
lun = scst_cm_next_lun++;
|
||||
if (lun == SCST_MAX_LUN)
|
||||
continue;
|
||||
if (scst_cm_is_lun_free(lun))
|
||||
break;
|
||||
};
|
||||
if (lun == SCST_MAX_LUN) {
|
||||
add_lun = true;
|
||||
while (1) {
|
||||
lun = scst_cm_next_lun++;
|
||||
if (lun == SCST_MAX_LUN)
|
||||
continue;
|
||||
if (scst_cm_is_lun_free(lun))
|
||||
break;
|
||||
}
|
||||
} else
|
||||
add_lun = false;
|
||||
|
||||
res = scst_acg_add_lun(scst_cm_tgt->default_acg,
|
||||
scst_cm_tgt->tgt_luns_kobj, dev, lun, false, false, &acg_dev);
|
||||
if (res != 0)
|
||||
goto out_err;
|
||||
if (add_lun) {
|
||||
res = scst_acg_add_lun(scst_cm_tgt->default_acg,
|
||||
scst_cm_tgt->tgt_luns_kobj, dev, lun, SCST_ADD_LUN_CM,
|
||||
&acg_dev);
|
||||
if (res != 0)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
scst_block_dev(dev);
|
||||
@@ -2578,13 +2587,15 @@ out_err:
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held and activities suspended */
|
||||
static void scst_cm_dev_unregister(struct scst_device *dev)
|
||||
static void scst_cm_dev_unregister(struct scst_device *dev, bool del_lun)
|
||||
{
|
||||
int i;
|
||||
struct scst_cm_desig *des, *t;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("dev %s, del_lun %d", dev->virt_name, del_lun);
|
||||
|
||||
list_for_each_entry_safe(des, t, &scst_cm_desig_list, cm_desig_list_entry) {
|
||||
if (des->desig_tgt_dev->dev == dev) {
|
||||
TRACE_DBG("Deleting des %p", des);
|
||||
@@ -2593,6 +2604,9 @@ static void scst_cm_dev_unregister(struct scst_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
if (!del_lun)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct list_head *head = &scst_cm_sess->sess_tgt_dev_list[i];
|
||||
@@ -2606,6 +2620,7 @@ static void scst_cm_dev_unregister(struct scst_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
@@ -2620,7 +2635,7 @@ int scst_cm_on_dev_register(struct scst_device *dev)
|
||||
if (!dev->handler->auto_cm_assignment_possible)
|
||||
goto out;
|
||||
|
||||
res = scst_cm_dev_register(dev);
|
||||
res = scst_cm_dev_register(dev, SCST_MAX_LUN);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -2632,12 +2647,87 @@ void scst_cm_on_dev_unregister(struct scst_device *dev)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_cm_dev_unregister(dev);
|
||||
scst_cm_dev_unregister(dev, true);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held and activities suspended */
|
||||
int scst_cm_on_add_acg(struct scst_acg *acg)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (scst_cm_tgt == NULL)
|
||||
goto out;
|
||||
|
||||
if (acg->tgt != scst_cm_tgt)
|
||||
goto out;
|
||||
|
||||
if (acg != scst_cm_tgt->default_acg) {
|
||||
PRINT_ERROR("Copy Manager does not support security groups");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held and activities suspended */
|
||||
void scst_cm_on_del_acg(struct scst_acg *acg)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held and activities suspended */
|
||||
int scst_cm_on_add_lun(struct scst_acg_dev *acg_dev, uint64_t lun,
|
||||
unsigned int *flags)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (acg_dev->acg != scst_cm_tgt->default_acg)
|
||||
goto out;
|
||||
|
||||
if (acg_dev->acg_dev_rd_only || acg_dev->dev->dev_rd_only) {
|
||||
PRINT_ERROR("Copy Manager does not support read only devices");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*flags &= ~SCST_ADD_LUN_GEN_UA;
|
||||
|
||||
res = scst_cm_dev_register(acg_dev->dev, lun);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held and activities suspended */
|
||||
bool scst_cm_on_del_lun(struct scst_acg_dev *acg_dev, bool gen_report_luns_changed)
|
||||
{
|
||||
bool res = gen_report_luns_changed;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (acg_dev->acg != scst_cm_tgt->default_acg)
|
||||
goto out;
|
||||
|
||||
scst_cm_dev_unregister(acg_dev->dev, false);
|
||||
|
||||
res = false;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be locked */
|
||||
static bool scst_cm_check_access_acg(const char *initiator_name,
|
||||
const struct scst_device *dev, const struct scst_acg *acg,
|
||||
@@ -3480,148 +3570,8 @@ static struct kobj_attribute scst_cm_allow_not_conn_copy_attr =
|
||||
scst_cm_allow_not_conn_copy_show,
|
||||
scst_cm_allow_not_conn_copy_store);
|
||||
|
||||
static ssize_t scst_cm_mgmt_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
static const char help[] =
|
||||
"Usage: echo \"add H:C:I:L\" >mgmt\n"
|
||||
" echo \"add VNAME\" >mgmt\n"
|
||||
" echo \"del H:C:I:L\" >mgmt\n"
|
||||
" echo \"del VNAME\" >mgmt\n";
|
||||
|
||||
return sprintf(buf, "%s", help);
|
||||
}
|
||||
|
||||
static int scst_cm_mgmt(struct scst_sysfs_work_item *work)
|
||||
{
|
||||
int res = 0;
|
||||
char *pp, *action, *devstr;
|
||||
unsigned int host, channel, id, lun;
|
||||
char *buf = work->buf;
|
||||
bool vdev;
|
||||
struct scst_device *d, *dev = NULL;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("buffer %s", buf);
|
||||
|
||||
pp = buf;
|
||||
action = scst_get_next_lexem(&pp);
|
||||
devstr = scst_get_next_lexem(&pp);
|
||||
if (*devstr == '\0') {
|
||||
PRINT_ERROR("%s", "Device required");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*scst_get_next_lexem(&pp) != '\0') {
|
||||
PRINT_ERROR("%s", "Too many parameters");
|
||||
res = -EINVAL;
|
||||
goto out_syntax_err;
|
||||
}
|
||||
|
||||
if (sscanf(devstr, "%u:%u:%u:%u", &host, &channel, &id, &lun) != 4) {
|
||||
vdev = true;
|
||||
TRACE_DBG("Virt dev %s", devstr);
|
||||
} else {
|
||||
vdev = false;
|
||||
TRACE_DBG("Pass-through dev %d:%d:%d:%d", host, channel, id, lun);
|
||||
}
|
||||
|
||||
res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
res = mutex_lock_interruptible(&scst_mutex);
|
||||
if (res != 0)
|
||||
goto out_resume;
|
||||
|
||||
list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
|
||||
if (vdev) {
|
||||
if ((d->scsi_dev == NULL) &&
|
||||
(strcmp(d->virt_name, devstr) == 0)) {
|
||||
dev = d;
|
||||
break;
|
||||
}
|
||||
} else if (d->scsi_dev != NULL &&
|
||||
d->scsi_dev->host->host_no == host &&
|
||||
d->scsi_dev->channel == channel &&
|
||||
d->scsi_dev->id == id &&
|
||||
d->scsi_dev->lun == lun) {
|
||||
dev = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dev == NULL) {
|
||||
PRINT_ERROR("Device %s not found", devstr);
|
||||
res = -EINVAL;
|
||||
goto out_unlock;
|
||||
} else
|
||||
TRACE_DBG("Dev %p (%s) found", dev, dev->virt_name);
|
||||
|
||||
if (strcasecmp("add", action) == 0)
|
||||
res = scst_cm_dev_register(dev);
|
||||
else if (strcasecmp("del", action) == 0)
|
||||
scst_cm_dev_unregister(dev);
|
||||
else {
|
||||
PRINT_ERROR("Action %s not understood", action);
|
||||
res = -EINVAL;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
out_resume:
|
||||
scst_resume_activity();
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_syntax_err:
|
||||
PRINT_ERROR("Syntax error on \"%s\"", buf);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static ssize_t scst_cm_mgmt_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buffer, size_t size)
|
||||
{
|
||||
int res;
|
||||
struct scst_sysfs_work_item *work;
|
||||
char *i_buf;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
i_buf = kasprintf(GFP_KERNEL, "%.*s", (int)size, buffer);
|
||||
if (i_buf == NULL) {
|
||||
PRINT_ERROR("Unable to alloc intermediate buffer with size %zd",
|
||||
size+1);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = scst_alloc_sysfs_work(scst_cm_mgmt, false, &work);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
work->buf = i_buf;
|
||||
|
||||
res = scst_sysfs_queue_wait_work(work);
|
||||
if (res == 0)
|
||||
res = size;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_cm_mgmt_attr =
|
||||
__ATTR(mgmt, S_IRUGO|S_IWUSR, scst_cm_mgmt_show, scst_cm_mgmt_store);
|
||||
|
||||
static const struct attribute *scst_cm_attrs[] = {
|
||||
static const struct attribute *scst_cm_tgtt_attrs[] = {
|
||||
&scst_cm_allow_not_conn_copy_attr.attr,
|
||||
&scst_cm_mgmt_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -3693,6 +3643,12 @@ static void scst_cm_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd)
|
||||
return;
|
||||
}
|
||||
|
||||
static int scst_cm_report_aen(struct scst_aen *aen)
|
||||
{
|
||||
/* Nothing to do */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct scst_tgt_template scst_cm_tgtt = {
|
||||
.name = SCST_CM_NAME,
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
|
||||
@@ -3710,9 +3666,10 @@ static struct scst_tgt_template scst_cm_tgtt = {
|
||||
.release = scst_cm_release,
|
||||
.xmit_response = scst_cm_xmit_response,
|
||||
.task_mgmt_fn_done = scst_cm_task_mgmt_fn_done,
|
||||
.report_aen = scst_cm_report_aen,
|
||||
.get_initiator_port_transport_id = scst_cm_get_initiator_port_transport_id,
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
.tgtt_attrs = scst_cm_attrs,
|
||||
.tgtt_attrs = scst_cm_tgtt_attrs,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
+43
-17
@@ -4373,8 +4373,8 @@ out:
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent,
|
||||
struct scst_device *dev, uint64_t lun, int read_only,
|
||||
bool gen_scst_report_luns_changed, struct scst_acg_dev **out_acg_dev)
|
||||
struct scst_device *dev, uint64_t lun, unsigned int flags,
|
||||
struct scst_acg_dev **out_acg_dev)
|
||||
{
|
||||
int res;
|
||||
struct scst_acg_dev *acg_dev;
|
||||
@@ -4395,7 +4395,7 @@ int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent,
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
acg_dev->acg_dev_rd_only = read_only;
|
||||
acg_dev->acg_dev_rd_only = ((flags & SCST_ADD_LUN_READ_ONLY) != 0);
|
||||
if (dev->dev_dif_mode & SCST_DIF_MODE_DEV_STORE) {
|
||||
/* Devices are allowed to store only CRCs */
|
||||
acg_dev->acg_dev_dif_guard_format = SCST_DIF_GUARD_FORMAT_CRC;
|
||||
@@ -4410,6 +4410,12 @@ int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent,
|
||||
list_add_tail(&acg_dev->acg_dev_list_entry, &acg->acg_dev_list);
|
||||
list_add_tail(&acg_dev->dev_acg_dev_list_entry, &dev->dev_acg_dev_list);
|
||||
|
||||
if (!(flags & SCST_ADD_LUN_CM)) {
|
||||
res = scst_cm_on_add_lun(acg_dev, lun, &flags);
|
||||
if (res != 0)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
|
||||
res = scst_alloc_add_tgt_dev(sess, acg_dev, &tgt_dev);
|
||||
if (res == -EPERM)
|
||||
@@ -4423,14 +4429,14 @@ int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent,
|
||||
|
||||
res = scst_acg_dev_sysfs_create(acg_dev, parent);
|
||||
if (res != 0)
|
||||
goto out_free;
|
||||
goto out_on_del;
|
||||
|
||||
if (gen_scst_report_luns_changed)
|
||||
if (flags & SCST_ADD_LUN_GEN_UA)
|
||||
scst_report_luns_changed(acg);
|
||||
|
||||
PRINT_INFO("Added device %s to group %s (LUN %lld, "
|
||||
"rd_only %d) to target %s", dev->virt_name, acg->acg_name,
|
||||
lun, read_only, acg->tgt ? acg->tgt->tgt_name : "?");
|
||||
"flags 0x%x) to target %s", dev->virt_name, acg->acg_name,
|
||||
lun, flags, acg->tgt ? acg->tgt->tgt_name : "?");
|
||||
|
||||
if (out_acg_dev != NULL)
|
||||
*out_acg_dev = acg_dev;
|
||||
@@ -4439,6 +4445,10 @@ out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_on_del:
|
||||
if (!(flags & SCST_ADD_LUN_CM))
|
||||
scst_cm_on_del_lun(acg_dev, false);
|
||||
|
||||
out_free:
|
||||
list_for_each_entry_safe(tgt_dev, tt, &tmp_tgt_dev_list,
|
||||
extra_tgt_dev_list_entry) {
|
||||
@@ -4450,7 +4460,7 @@ out_free:
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun,
|
||||
bool gen_scst_report_luns_changed)
|
||||
bool gen_report_luns_changed)
|
||||
{
|
||||
int res = 0;
|
||||
struct scst_acg_dev *acg_dev = NULL, *a;
|
||||
@@ -4470,6 +4480,8 @@ int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun,
|
||||
goto out;
|
||||
}
|
||||
|
||||
gen_report_luns_changed = scst_cm_on_del_lun(acg_dev, gen_report_luns_changed);
|
||||
|
||||
list_for_each_entry_safe(tgt_dev, tt, &acg_dev->dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
if (tgt_dev->acg_dev == acg_dev)
|
||||
@@ -4478,7 +4490,7 @@ int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun,
|
||||
|
||||
scst_del_free_acg_dev(acg_dev, true);
|
||||
|
||||
if (gen_scst_report_luns_changed)
|
||||
if (gen_report_luns_changed)
|
||||
scst_report_luns_changed(acg);
|
||||
|
||||
PRINT_INFO("Removed LUN %lld from group %s (target %s)",
|
||||
@@ -4490,16 +4502,18 @@ out:
|
||||
}
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt,
|
||||
const char *acg_name, bool tgt_acg)
|
||||
int scst_alloc_add_acg(struct scst_tgt *tgt, const char *acg_name,
|
||||
bool tgt_acg, struct scst_acg **out_acg)
|
||||
{
|
||||
struct scst_acg *acg;
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
acg = kzalloc(sizeof(*acg), GFP_KERNEL);
|
||||
if (acg == NULL) {
|
||||
PRINT_ERROR("%s", "Allocation of acg failed");
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -4512,9 +4526,14 @@ struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt,
|
||||
acg->acg_name = kstrdup(acg_name, GFP_KERNEL);
|
||||
if (acg->acg_name == NULL) {
|
||||
PRINT_ERROR("%s", "Allocation of acg_name failed");
|
||||
res = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
res = scst_cm_on_add_acg(acg);
|
||||
if (res != 0)
|
||||
goto out_undup;
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
acg->addr_method = tgt && tgt->tgtt ? tgt->tgtt->preferred_addr_method
|
||||
: SCST_LUN_ADDR_METHOD_PERIPHERAL;
|
||||
@@ -4527,30 +4546,35 @@ struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt,
|
||||
acg->addr_method = tgt->tgtt->preferred_addr_method;
|
||||
|
||||
if (tgt_acg) {
|
||||
int rc;
|
||||
|
||||
TRACE_DBG("Adding acg '%s' to device '%s' acg_list", acg_name,
|
||||
tgt->tgt_name);
|
||||
list_add_tail(&acg->acg_list_entry, &tgt->tgt_acg_list);
|
||||
acg->tgt_acg = 1;
|
||||
|
||||
rc = scst_acg_sysfs_create(tgt, acg);
|
||||
if (rc != 0)
|
||||
res = scst_acg_sysfs_create(tgt, acg);
|
||||
if (res != 0)
|
||||
goto out_del;
|
||||
}
|
||||
|
||||
kobject_get(&tgt->tgt_kobj);
|
||||
#endif
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES(acg);
|
||||
return acg;
|
||||
*out_acg = acg;
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
out_del:
|
||||
list_del(&acg->acg_list_entry);
|
||||
#endif
|
||||
|
||||
out_undup:
|
||||
kfree(acg->acg_name);
|
||||
|
||||
out_free:
|
||||
kfree(acg);
|
||||
acg = NULL;
|
||||
@@ -4573,6 +4597,8 @@ static void scst_del_acg(struct scst_acg *acg)
|
||||
scst_assert_activity_suspended();
|
||||
lockdep_assert_held(&scst_mutex);
|
||||
|
||||
scst_cm_on_del_acg(acg);
|
||||
|
||||
list_for_each_entry_safe(acg_dev, acg_dev_tmp, &acg->acg_dev_list,
|
||||
acg_dev_list_entry)
|
||||
scst_del_acg_dev(acg_dev, true);
|
||||
|
||||
@@ -550,8 +550,8 @@ struct scst_tgt *scst_register_target(struct scst_tgt_template *vtt,
|
||||
if (rc < 0)
|
||||
goto out_unlock;
|
||||
|
||||
tgt->default_acg = scst_alloc_add_acg(tgt, tgt->tgt_name, false);
|
||||
if (tgt->default_acg == NULL)
|
||||
rc = scst_alloc_add_acg(tgt, tgt->tgt_name, false, &tgt->default_acg);
|
||||
if (rc != 0)
|
||||
goto out_sysfs_del;
|
||||
#endif
|
||||
|
||||
@@ -2650,11 +2650,9 @@ static int __init init_scst(void)
|
||||
goto out_sysfs_cleanup;
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
scst_default_acg = scst_alloc_add_acg(NULL, SCST_DEFAULT_ACG_NAME, false);
|
||||
if (scst_default_acg == NULL) {
|
||||
res = -ENOMEM;
|
||||
res = scst_alloc_add_acg(NULL, SCST_DEFAULT_ACG_NAME, false, &scst_default_acg);
|
||||
if (res != 0)
|
||||
goto out_destroy_sgv_pool;
|
||||
}
|
||||
#endif
|
||||
|
||||
res = scsi_register_interface(&scst_interface);
|
||||
|
||||
+15
-5
@@ -347,8 +347,8 @@ int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev);
|
||||
void scst_free_device(struct scst_device *dev);
|
||||
bool scst_device_is_exported(struct scst_device *dev);
|
||||
|
||||
struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt,
|
||||
const char *acg_name, bool tgt_acg);
|
||||
int scst_alloc_add_acg(struct scst_tgt *tgt, const char *acg_name,
|
||||
bool tgt_acg, struct scst_acg **out_acg);
|
||||
int scst_del_free_acg(struct scst_acg *acg, bool close_sessions);
|
||||
void scst_get_acg(struct scst_acg *acg);
|
||||
void scst_put_acg(struct scst_acg *acg);
|
||||
@@ -363,11 +363,14 @@ void scst_sess_free_tgt_devs(struct scst_session *sess);
|
||||
struct scst_tgt_dev *scst_lookup_tgt_dev(struct scst_session *sess, u64 lun);
|
||||
void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA);
|
||||
|
||||
#define SCST_ADD_LUN_READ_ONLY 1
|
||||
#define SCST_ADD_LUN_GEN_UA 2
|
||||
#define SCST_ADD_LUN_CM 4
|
||||
int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent,
|
||||
struct scst_device *dev, uint64_t lun, int read_only,
|
||||
bool gen_scst_report_luns_changed, struct scst_acg_dev **out_acg_dev);
|
||||
struct scst_device *dev, uint64_t lun, unsigned int flags,
|
||||
struct scst_acg_dev **out_acg_dev);
|
||||
int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun,
|
||||
bool gen_scst_report_luns_changed);
|
||||
bool gen_report_luns_changed);
|
||||
|
||||
int scst_acg_add_acn(struct scst_acg *acg, const char *name);
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
@@ -857,6 +860,13 @@ static inline bool scst_lba1_inside_lba2(int64_t lba1,
|
||||
int scst_cm_on_dev_register(struct scst_device *dev);
|
||||
void scst_cm_on_dev_unregister(struct scst_device *dev);
|
||||
|
||||
int scst_cm_on_add_acg(struct scst_acg *acg);
|
||||
void scst_cm_on_del_acg(struct scst_acg *acg);
|
||||
int scst_cm_on_add_lun(struct scst_acg_dev *acg_dev, uint64_t lun,
|
||||
unsigned int *flags);
|
||||
bool scst_cm_on_del_lun(struct scst_acg_dev *acg_dev,
|
||||
bool gen_report_luns_changed);
|
||||
|
||||
int scst_cm_parse_descriptors(struct scst_cmd *cmd);
|
||||
void scst_cm_free_descriptors(struct scst_cmd *cmd);
|
||||
|
||||
|
||||
@@ -948,8 +948,8 @@ static int scst_proc_group_add(const char *p, unsigned int addr_method)
|
||||
}
|
||||
strlcpy(name, p, len);
|
||||
|
||||
acg = scst_alloc_add_acg(NULL, name, false);
|
||||
if (acg == NULL) {
|
||||
res = scst_alloc_add_acg(NULL, name, false, &acg);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("scst_alloc_add_acg() (name %s) failed", name);
|
||||
goto out_free;
|
||||
}
|
||||
@@ -969,6 +969,7 @@ out_free_acg:
|
||||
|
||||
out_free:
|
||||
kfree(name);
|
||||
goto out;
|
||||
|
||||
out_nomem:
|
||||
res = -ENOMEM;
|
||||
@@ -2069,7 +2070,8 @@ static ssize_t scst_proc_groups_devices_write(struct file *file,
|
||||
}
|
||||
}
|
||||
|
||||
rc = scst_acg_add_lun(acg, NULL, dev, virt_lun, read_only,
|
||||
rc = scst_acg_add_lun(acg, NULL, dev, virt_lun,
|
||||
read_only ? SCST_ADD_LUN_READ_ONLY : 0,
|
||||
false, NULL);
|
||||
if (rc) {
|
||||
res = rc;
|
||||
|
||||
@@ -1327,6 +1327,7 @@ static int __scst_process_luns_mgmt_store(char *buffer,
|
||||
case SCST_LUN_ACTION_REPLACE:
|
||||
{
|
||||
bool dev_replaced = false;
|
||||
unsigned int flags = 0;
|
||||
|
||||
e = scst_get_next_lexem(&pp);
|
||||
res = kstrtoul(e, 0, &virt_lun);
|
||||
@@ -1414,9 +1415,13 @@ static int __scst_process_luns_mgmt_store(char *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
if (read_only)
|
||||
flags |= SCST_ADD_LUN_READ_ONLY;
|
||||
if (!dev_replaced)
|
||||
flags |= SCST_ADD_LUN_GEN_UA;
|
||||
res = scst_acg_add_lun(acg,
|
||||
tgt_kobj ? tgt->tgt_luns_kobj : acg->luns_kobj,
|
||||
dev, virt_lun, read_only, !dev_replaced, NULL);
|
||||
dev, virt_lun, flags, NULL);
|
||||
if (res != 0)
|
||||
goto out_unlock;
|
||||
|
||||
@@ -2174,8 +2179,8 @@ static int scst_process_ini_group_mgmt_store(char *buffer,
|
||||
res = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
acg = scst_alloc_add_acg(tgt, p, true);
|
||||
if (acg == NULL)
|
||||
res = scst_alloc_add_acg(tgt, p, true, &acg);
|
||||
if (res != 0)
|
||||
goto out_unlock;
|
||||
break;
|
||||
case SCST_INI_GROUP_ACTION_DEL:
|
||||
|
||||
Reference in New Issue
Block a user