mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-19 11:41:26 +00:00
Device sysfs locking reconsidered to remove recently introduced deadlock possibility.
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1361 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -1811,6 +1811,9 @@ struct scst_device {
|
|||||||
*/
|
*/
|
||||||
struct rw_semaphore dev_attr_rwsem;
|
struct rw_semaphore dev_attr_rwsem;
|
||||||
|
|
||||||
|
/* Used to serialize all the device sysfs calls */
|
||||||
|
struct mutex dev_sysfs_mutex;
|
||||||
|
|
||||||
struct kobject dev_kobj; /* kobject for this struct */
|
struct kobject dev_kobj; /* kobject for this struct */
|
||||||
struct kobject *dev_exp_kobj; /* exported groups */
|
struct kobject *dev_exp_kobj; /* exported groups */
|
||||||
|
|
||||||
|
|||||||
@@ -277,12 +277,6 @@ struct vdev_type_funcs {
|
|||||||
void (*vdev_del) (struct scst_vdisk_dev *virt_dev);
|
void (*vdev_del) (struct scst_vdisk_dev *virt_dev);
|
||||||
struct scst_vdisk_dev *(*vdev_find) (const char *name);
|
struct scst_vdisk_dev *(*vdev_find) (const char *name);
|
||||||
|
|
||||||
int (*parse_cmd) (struct vdev_type *vdt, char *p, int *action);
|
|
||||||
|
|
||||||
/* Supposed to be called under scst_vdisk_mutex */
|
|
||||||
int (*perform_cmd) (struct vdev_type *vdt, int action, char *p,
|
|
||||||
char *name);
|
|
||||||
|
|
||||||
int (*parse_option) (struct scst_vdisk_dev *virt_dev, char *p);
|
int (*parse_option) (struct scst_vdisk_dev *virt_dev, char *p);
|
||||||
|
|
||||||
int (*pre_register) (struct scst_vdisk_dev *virt_dev);
|
int (*pre_register) (struct scst_vdisk_dev *virt_dev);
|
||||||
@@ -404,6 +398,9 @@ static ssize_t vdisk_sysfs_filename_show(struct kobject *kobj,
|
|||||||
static ssize_t vdisk_sysfs_resync_size_store(struct kobject *kobj,
|
static ssize_t vdisk_sysfs_resync_size_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 ssize_t vcdrom_sysfs_filename_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||||
|
|
||||||
static struct kobj_attribute vdisk_size_attr =
|
static struct kobj_attribute vdisk_size_attr =
|
||||||
__ATTR(size, S_IRUGO, vdisk_sysfs_size_show, NULL);
|
__ATTR(size, S_IRUGO, vdisk_sysfs_size_show, NULL);
|
||||||
static struct kobj_attribute vdisk_blocksize_attr =
|
static struct kobj_attribute vdisk_blocksize_attr =
|
||||||
@@ -423,6 +420,10 @@ static struct kobj_attribute vdisk_filename_attr =
|
|||||||
static struct kobj_attribute vdisk_resync_size_attr =
|
static struct kobj_attribute vdisk_resync_size_attr =
|
||||||
__ATTR(resync_size, S_IWUSR, NULL, vdisk_sysfs_resync_size_store);
|
__ATTR(resync_size, S_IWUSR, NULL, vdisk_sysfs_resync_size_store);
|
||||||
|
|
||||||
|
static struct kobj_attribute vcdrom_filename_attr =
|
||||||
|
__ATTR(filename, S_IRUGO|S_IWUSR, vdisk_sysfs_filename_show,
|
||||||
|
vcdrom_sysfs_filename_store);
|
||||||
|
|
||||||
static const struct attribute *vdisk_fileio_attrs[] = {
|
static const struct attribute *vdisk_fileio_attrs[] = {
|
||||||
&vdisk_size_attr.attr,
|
&vdisk_size_attr.attr,
|
||||||
&vdisk_blocksize_attr.attr,
|
&vdisk_blocksize_attr.attr,
|
||||||
@@ -457,12 +458,13 @@ static const struct attribute *vdisk_nullio_attrs[] = {
|
|||||||
static const struct attribute *vcdrom_attrs[] = {
|
static const struct attribute *vcdrom_attrs[] = {
|
||||||
&vdisk_size_attr.attr,
|
&vdisk_size_attr.attr,
|
||||||
&vdisk_removable_attr.attr,
|
&vdisk_removable_attr.attr,
|
||||||
&vdisk_filename_attr.attr,
|
&vcdrom_filename_attr.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_SCST_PROC */
|
#endif /* CONFIG_SCST_PROC */
|
||||||
|
|
||||||
|
/* Protects vdisks addition/deletion and related activities, like search */
|
||||||
static DEFINE_MUTEX(scst_vdisk_mutex);
|
static DEFINE_MUTEX(scst_vdisk_mutex);
|
||||||
|
|
||||||
/* Both protected by scst_vdisk_mutex */
|
/* Both protected by scst_vdisk_mutex */
|
||||||
@@ -2923,12 +2925,16 @@ static void vdisk_report_registering(const struct scst_vdisk_dev *virt_dev)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scst_vdisk_mutex supposed to be held */
|
static int vdisk_resync_size(struct scst_vdisk_dev *virt_dev)
|
||||||
static int __vdisk_resync_size(struct scst_vdisk_dev *virt_dev)
|
|
||||||
{
|
{
|
||||||
loff_t file_size;
|
loff_t file_size;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There's no need in any lock here, because SCST core serializes
|
||||||
|
* all device sysfs calls.
|
||||||
|
*/
|
||||||
|
|
||||||
if (!virt_dev->nullio) {
|
if (!virt_dev->nullio) {
|
||||||
res = vdisk_get_file_size(virt_dev->file_name,
|
res = vdisk_get_file_size(virt_dev->file_name,
|
||||||
virt_dev->blockio, &file_size);
|
virt_dev->blockio, &file_size);
|
||||||
@@ -2969,26 +2975,6 @@ out:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scst_vdisk_mutex supposed to be held */
|
|
||||||
static int vdisk_resync_size(struct vdev_type *vdt, char *p, const char *name)
|
|
||||||
{
|
|
||||||
struct scst_vdisk_dev *virt_dev;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
virt_dev = vdt->vfns.vdev_find(name);
|
|
||||||
if (virt_dev == NULL) {
|
|
||||||
PRINT_ERROR("Device %s not found", name);
|
|
||||||
res = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = __vdisk_resync_size(virt_dev);
|
|
||||||
|
|
||||||
out:
|
|
||||||
TRACE_EXIT_RES(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vdev_init(struct vdev_type *vdt, struct scst_vdisk_dev *virt_dev)
|
static void vdev_init(struct vdev_type *vdt, struct scst_vdisk_dev *virt_dev)
|
||||||
{
|
{
|
||||||
memset(virt_dev, 0, sizeof(*virt_dev));
|
memset(virt_dev, 0, sizeof(*virt_dev));
|
||||||
@@ -3393,37 +3379,6 @@ static struct scst_vdisk_dev *vcdrom_find(const char *name)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vdisk_parse_cmd(struct vdev_type *vdt, char *p, int *action)
|
|
||||||
{
|
|
||||||
int res = -EINVAL;
|
|
||||||
|
|
||||||
TRACE_ENTRY();
|
|
||||||
|
|
||||||
if (!strncmp("resync_size", p, 11)) {
|
|
||||||
res = 11;
|
|
||||||
p += res;
|
|
||||||
*action = VDISK_ACTION_RESYNC_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE_EXIT_RES(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* scst_vdisk_mutex supposed to be held */
|
|
||||||
static int vdisk_perform_cmd(struct vdev_type *vdt, int action, char *p,
|
|
||||||
char *name)
|
|
||||||
{
|
|
||||||
int res = -EINVAL;
|
|
||||||
|
|
||||||
TRACE_ENTRY();
|
|
||||||
|
|
||||||
if (action == VDISK_ACTION_RESYNC_SIZE)
|
|
||||||
res = vdisk_resync_size(vdt, p, name);
|
|
||||||
|
|
||||||
TRACE_EXIT_RES(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vcdrom_init(struct vdev_type *vdt,
|
static void vcdrom_init(struct vdev_type *vdt,
|
||||||
struct scst_vdisk_dev *virt_dev)
|
struct scst_vdisk_dev *virt_dev)
|
||||||
{
|
{
|
||||||
@@ -3460,29 +3415,48 @@ static int vcdrom_pre_register(struct scst_vdisk_dev *virt_dev)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scst_vdisk_mutex supposed to be held */
|
static int vcdrom_change(struct scst_vdisk_dev *virt_dev,
|
||||||
static int vcdrom_change(struct vdev_type *vdt, char *p, const char *name)
|
const char *buffer, int length)
|
||||||
{
|
{
|
||||||
loff_t err;
|
loff_t err;
|
||||||
struct scst_vdisk_dev *virt_dev;
|
char *old_fn, *i_buf, *p, *pp;
|
||||||
char *file_name, *fn = NULL, *old_fn;
|
const char *file_name = NULL;
|
||||||
int len;
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
virt_dev = vdt->vfns.vdev_find(name);
|
TRACE_ENTRY();
|
||||||
if (virt_dev == NULL) {
|
|
||||||
PRINT_ERROR("Virtual device with name "
|
/*
|
||||||
"%s not found", name);
|
* There's no need in any lock here, because SCST core serializes
|
||||||
res = -EINVAL;
|
* all device sysfs calls.
|
||||||
|
*/
|
||||||
|
|
||||||
|
i_buf = kmalloc(length+1, GFP_KERNEL);
|
||||||
|
if (i_buf == NULL) {
|
||||||
|
PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
|
||||||
|
length+1);
|
||||||
|
res = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(i_buf, buffer, length);
|
||||||
|
i_buf[length] = '\0';
|
||||||
|
p = i_buf;
|
||||||
|
|
||||||
while (isspace(*p) && *p != '\0')
|
while (isspace(*p) && *p != '\0')
|
||||||
p++;
|
p++;
|
||||||
file_name = p;
|
file_name = p;
|
||||||
while (!isspace(*p) && *p != '\0')
|
p = &i_buf[length-1];
|
||||||
p++;
|
pp = p;
|
||||||
*p++ = '\0';
|
while (isspace(*p) && *p != '\0') {
|
||||||
|
pp = p;
|
||||||
|
p--;
|
||||||
|
}
|
||||||
|
*pp = '\0';
|
||||||
|
|
||||||
|
res = scst_suspend_activity(true);
|
||||||
|
if (res != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (*file_name == '\0') {
|
if (*file_name == '\0') {
|
||||||
virt_dev->cdrom_empty = 1;
|
virt_dev->cdrom_empty = 1;
|
||||||
TRACE_DBG("%s", "No media");
|
TRACE_DBG("%s", "No media");
|
||||||
@@ -3490,20 +3464,20 @@ static int vcdrom_change(struct vdev_type *vdt, char *p, const char *name)
|
|||||||
PRINT_ERROR("File path \"%s\" is not "
|
PRINT_ERROR("File path \"%s\" is not "
|
||||||
"absolute", file_name);
|
"absolute", file_name);
|
||||||
res = -EINVAL;
|
res = -EINVAL;
|
||||||
goto out;
|
goto out_resume;
|
||||||
} else
|
} else
|
||||||
virt_dev->cdrom_empty = 0;
|
virt_dev->cdrom_empty = 0;
|
||||||
|
|
||||||
old_fn = virt_dev->file_name;
|
old_fn = virt_dev->file_name;
|
||||||
|
|
||||||
if (!virt_dev->cdrom_empty) {
|
if (!virt_dev->cdrom_empty) {
|
||||||
len = strlen(file_name) + 1;
|
int len = strlen(file_name) + 1;
|
||||||
fn = kmalloc(len, GFP_KERNEL);
|
char *fn = kmalloc(len, GFP_KERNEL);
|
||||||
if (fn == NULL) {
|
if (fn == NULL) {
|
||||||
TRACE(TRACE_OUT_OF_MEM, "%s",
|
TRACE(TRACE_OUT_OF_MEM, "%s",
|
||||||
"Allocation of file_name failed");
|
"Allocation of file_name failed");
|
||||||
res = -ENOMEM;
|
res = -ENOMEM;
|
||||||
goto out;
|
goto out_resume;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(fn, file_name, len);
|
strncpy(fn, file_name, len);
|
||||||
@@ -3518,15 +3492,11 @@ static int vcdrom_change(struct vdev_type *vdt, char *p, const char *name)
|
|||||||
virt_dev->file_name = NULL;
|
virt_dev->file_name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = scst_suspend_activity(true);
|
|
||||||
if (res != 0)
|
|
||||||
goto out_free;
|
|
||||||
|
|
||||||
if (virt_dev->prevent_allow_medium_removal) {
|
if (virt_dev->prevent_allow_medium_removal) {
|
||||||
PRINT_ERROR("Prevent medium removal for "
|
PRINT_ERROR("Prevent medium removal for "
|
||||||
"virtual device with name %s", name);
|
"virtual device with name %s", virt_dev->name);
|
||||||
res = -EINVAL;
|
res = -EINVAL;
|
||||||
goto out_free_resume;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
virt_dev->file_size = err;
|
virt_dev->file_size = err;
|
||||||
@@ -3556,52 +3526,40 @@ out_resume:
|
|||||||
scst_resume_activity();
|
scst_resume_activity();
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
TRACE_EXIT_RES(res);
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
|
kfree(virt_dev->file_name);
|
||||||
virt_dev->file_name = old_fn;
|
virt_dev->file_name = old_fn;
|
||||||
kfree(fn);
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
out_free_resume:
|
|
||||||
virt_dev->file_name = old_fn;
|
|
||||||
kfree(fn);
|
|
||||||
goto out_resume;
|
goto out_resume;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vcdrom_parse_cmd(struct vdev_type *vdt, char *p, int *action)
|
|
||||||
{
|
|
||||||
int res = -EINVAL;
|
|
||||||
|
|
||||||
TRACE_ENTRY();
|
|
||||||
|
|
||||||
if (!strncmp("change", p, 6)) {
|
|
||||||
res = 6;
|
|
||||||
p += res;
|
|
||||||
*action = VCDROM_ACTION_CHANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE_EXIT_RES(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* scst_vdisk_mutex supposed to be held */
|
|
||||||
static int vcdrom_perform_cmd(struct vdev_type *vdt, int action, char *p,
|
|
||||||
char *name)
|
|
||||||
{
|
|
||||||
int res = -EINVAL;
|
|
||||||
|
|
||||||
TRACE_ENTRY();
|
|
||||||
|
|
||||||
if (action == VCDROM_ACTION_CHANGE)
|
|
||||||
res = vcdrom_change(vdt, p, name);
|
|
||||||
|
|
||||||
TRACE_EXIT_RES(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef CONFIG_SCST_PROC
|
#ifndef CONFIG_SCST_PROC
|
||||||
|
|
||||||
|
static ssize_t vcdrom_sysfs_filename_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
struct scst_device *dev;
|
||||||
|
struct scst_vdisk_dev *virt_dev;
|
||||||
|
|
||||||
|
TRACE_ENTRY();
|
||||||
|
|
||||||
|
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||||
|
virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
|
||||||
|
|
||||||
|
res = vcdrom_change(virt_dev, buf, count);
|
||||||
|
if (res != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
res = count;
|
||||||
|
|
||||||
|
out:
|
||||||
|
TRACE_EXIT_RES(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static int vdisk_mgmt_cmd(const char *buffer, int length,
|
static int vdisk_mgmt_cmd(const char *buffer, int length,
|
||||||
struct vdev_type *vdt)
|
struct vdev_type *vdt)
|
||||||
{
|
{
|
||||||
@@ -3618,6 +3576,7 @@ static int vdisk_mgmt_cmd(const char *buffer, int length,
|
|||||||
if (i_buf == NULL) {
|
if (i_buf == NULL) {
|
||||||
PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
|
PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
|
||||||
length+1);
|
length+1);
|
||||||
|
res = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3639,15 +3598,9 @@ static int vdisk_mgmt_cmd(const char *buffer, int length,
|
|||||||
p += 5;
|
p += 5;
|
||||||
action = VDEV_ACTION_CLOSE;
|
action = VDEV_ACTION_CLOSE;
|
||||||
} else {
|
} else {
|
||||||
int n;
|
PRINT_ERROR("Unknown action \"%s\"", p);
|
||||||
n = vdt->vfns.parse_cmd(vdt, p, &action);
|
res = -EINVAL;
|
||||||
if (n > 0)
|
goto out_up;
|
||||||
p += n;
|
|
||||||
else {
|
|
||||||
PRINT_ERROR("Unknown action \"%s\"", p);
|
|
||||||
res = -EINVAL;
|
|
||||||
goto out_up;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isspace(*p)) {
|
if (!isspace(*p)) {
|
||||||
@@ -3681,11 +3634,9 @@ static int vdisk_mgmt_cmd(const char *buffer, int length,
|
|||||||
res = vdt->vfns.vdev_close(vdt, name);
|
res = vdt->vfns.vdev_close(vdt, name);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
goto out_up;
|
goto out_up;
|
||||||
} else {
|
} else
|
||||||
res = vdt->vfns.perform_cmd(vdt, action, p, name);
|
sBUG();
|
||||||
if (res != 0)
|
|
||||||
goto out_up;
|
|
||||||
}
|
|
||||||
res = length;
|
res = length;
|
||||||
|
|
||||||
out_up:
|
out_up:
|
||||||
@@ -3880,20 +3831,12 @@ static ssize_t vdisk_sysfs_resync_size_store(struct kobject *kobj,
|
|||||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||||
virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
|
virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
|
||||||
|
|
||||||
if (mutex_lock_interruptible(&scst_vdisk_mutex) != 0) {
|
res = vdisk_resync_size(virt_dev);
|
||||||
res = -EINTR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = __vdisk_resync_size(virt_dev);
|
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
res = count;
|
res = count;
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
mutex_unlock(&scst_vdisk_mutex);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
TRACE_EXIT_RES(res);
|
TRACE_EXIT_RES(res);
|
||||||
return res;
|
return res;
|
||||||
@@ -3993,6 +3936,7 @@ static int vdisk_proc_mgmt_cmd(const char *buffer, int length,
|
|||||||
if (i_buf == NULL) {
|
if (i_buf == NULL) {
|
||||||
PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
|
PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
|
||||||
length+1);
|
length+1);
|
||||||
|
res = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4226,7 +4170,7 @@ static int vdisk_proc_mgmt_cmd(const char *buffer, int length,
|
|||||||
goto out_up;
|
goto out_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = __vdisk_resync_size(virt_dev);
|
res = vdisk_resync_size(virt_dev);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
goto out_up;
|
goto out_up;
|
||||||
}
|
}
|
||||||
@@ -4296,6 +4240,26 @@ out:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* scst_vdisk_mutex supposed to be held */
|
||||||
|
static int vcdrom_proc_change(struct vdev_type *vdt, char *p, const char *name)
|
||||||
|
{
|
||||||
|
struct scst_vdisk_dev *virt_dev;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
virt_dev = vdt->vfns.vdev_find(name);
|
||||||
|
if (virt_dev == NULL) {
|
||||||
|
PRINT_ERROR("Virtual device with name "
|
||||||
|
"%s not found", name);
|
||||||
|
res = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = vcdrom_change(virt_dev, p, strlen(p) + 1);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static int vcdrom_proc_mgmt_cmd(const char *buffer, int length,
|
static int vcdrom_proc_mgmt_cmd(const char *buffer, int length,
|
||||||
struct scst_dev_type *dev_type)
|
struct scst_dev_type *dev_type)
|
||||||
{
|
{
|
||||||
@@ -4312,6 +4276,7 @@ static int vcdrom_proc_mgmt_cmd(const char *buffer, int length,
|
|||||||
if (i_buf == NULL) {
|
if (i_buf == NULL) {
|
||||||
PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
|
PRINT_ERROR("Unable to alloc intermediate buffer with size %d",
|
||||||
length+1);
|
length+1);
|
||||||
|
res = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4365,7 +4330,7 @@ static int vcdrom_proc_mgmt_cmd(const char *buffer, int length,
|
|||||||
goto out_up;
|
goto out_up;
|
||||||
} else if (action == 1) {
|
} else if (action == 1) {
|
||||||
/* change */
|
/* change */
|
||||||
res = vcdrom_change(&vcdrom_type.parent_vdt, p, name);
|
res = vcdrom_proc_change(&vcdrom_type.parent_vdt, p, name);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
goto out_up;
|
goto out_up;
|
||||||
} else {
|
} else {
|
||||||
@@ -4558,7 +4523,7 @@ static void __init init_fileio_type(void)
|
|||||||
|
|
||||||
vdt->vdt_name = "FILEIO";
|
vdt->vdt_name = "FILEIO";
|
||||||
vdt->help_string = "Usage:\n"
|
vdt->help_string = "Usage:\n"
|
||||||
" echo \"open|close|resync_size NAME [FILE_NAME "
|
" echo \"open|close NAME [FILE_NAME "
|
||||||
"[BLOCK_SIZE] [WRITE_THROUGH] [READ_ONLY] [O_DIRECT] "
|
"[BLOCK_SIZE] [WRITE_THROUGH] [READ_ONLY] [O_DIRECT] "
|
||||||
"[NV_CACHE] [REMOVABLE]]\" >mgmt\n";
|
"[NV_CACHE] [REMOVABLE]]\" >mgmt\n";
|
||||||
|
|
||||||
@@ -4566,8 +4531,6 @@ static void __init init_fileio_type(void)
|
|||||||
|
|
||||||
vdt->vfns.vdev_add = vdisk_add;
|
vdt->vfns.vdev_add = vdisk_add;
|
||||||
vdt->vfns.vdev_find = vdisk_find;
|
vdt->vfns.vdev_find = vdisk_find;
|
||||||
vdt->vfns.parse_cmd = vdisk_parse_cmd;
|
|
||||||
vdt->vfns.perform_cmd = vdisk_perform_cmd;
|
|
||||||
vdt->vfns.parse_option = vdisk_fileio_parse_option;
|
vdt->vfns.parse_option = vdisk_fileio_parse_option;
|
||||||
vdt->vfns.pre_register = vdisk_fileio_pre_register;
|
vdt->vfns.pre_register = vdisk_fileio_pre_register;
|
||||||
|
|
||||||
@@ -4582,7 +4545,7 @@ static void __init init_blockio_type(void)
|
|||||||
|
|
||||||
vdt->vdt_name = "BLOCKIO";
|
vdt->vdt_name = "BLOCKIO";
|
||||||
vdt->help_string = "Usage:\n"
|
vdt->help_string = "Usage:\n"
|
||||||
" echo \"open|close|resync_size NAME [DEVICE_NAME "
|
" echo \"open|close NAME [DEVICE_NAME "
|
||||||
"[BLOCK_SIZE] [READ_ONLY] [REMOVABLE]]\" >mgmt\n";
|
"[BLOCK_SIZE] [READ_ONLY] [REMOVABLE]]\" >mgmt\n";
|
||||||
|
|
||||||
blockio_type.parent_vdt_vfns = vdt->vfns;
|
blockio_type.parent_vdt_vfns = vdt->vfns;
|
||||||
@@ -4590,8 +4553,6 @@ static void __init init_blockio_type(void)
|
|||||||
vdt->vfns.vdev_init = vdisk_blockio_init;
|
vdt->vfns.vdev_init = vdisk_blockio_init;
|
||||||
vdt->vfns.vdev_add = vdisk_add;
|
vdt->vfns.vdev_add = vdisk_add;
|
||||||
vdt->vfns.vdev_find = vdisk_find;
|
vdt->vfns.vdev_find = vdisk_find;
|
||||||
vdt->vfns.parse_cmd = vdisk_parse_cmd;
|
|
||||||
vdt->vfns.perform_cmd = vdisk_perform_cmd;
|
|
||||||
vdt->vfns.parse_option = vdisk_parse_option;
|
vdt->vfns.parse_option = vdisk_parse_option;
|
||||||
vdt->vfns.pre_register = vdisk_blockio_pre_register;
|
vdt->vfns.pre_register = vdisk_blockio_pre_register;
|
||||||
|
|
||||||
@@ -4613,9 +4574,7 @@ static void __init init_nullio_type(void)
|
|||||||
vdt->vfns.vdev_init = vdisk_nullio_init;
|
vdt->vfns.vdev_init = vdisk_nullio_init;
|
||||||
vdt->vfns.vdev_add = vdisk_add;
|
vdt->vfns.vdev_add = vdisk_add;
|
||||||
vdt->vfns.vdev_find = vdisk_find;
|
vdt->vfns.vdev_find = vdisk_find;
|
||||||
vdt->vfns.parse_cmd = vdisk_parse_cmd;
|
|
||||||
vdt->vfns.parse_option = vdisk_parse_option;
|
vdt->vfns.parse_option = vdisk_parse_option;
|
||||||
vdt->vfns.perform_cmd = vdisk_perform_cmd;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -4634,8 +4593,6 @@ static void __init init_vcdrom_type(void)
|
|||||||
vdt->vfns.vdev_init = vcdrom_init;
|
vdt->vfns.vdev_init = vcdrom_init;
|
||||||
vdt->vfns.vdev_add = vcdrom_add;
|
vdt->vfns.vdev_add = vcdrom_add;
|
||||||
vdt->vfns.vdev_find = vcdrom_find;
|
vdt->vfns.vdev_find = vcdrom_find;
|
||||||
vdt->vfns.parse_cmd = vcdrom_parse_cmd;
|
|
||||||
vdt->vfns.perform_cmd = vcdrom_perform_cmd;
|
|
||||||
vdt->vfns.pre_register = vcdrom_pre_register;
|
vdt->vfns.pre_register = vcdrom_pre_register;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1334,7 +1334,6 @@ out:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called under scst_mutex and suspended activity */
|
|
||||||
void scst_free_device(struct scst_device *dev)
|
void scst_free_device(struct scst_device *dev)
|
||||||
{
|
{
|
||||||
TRACE_ENTRY();
|
TRACE_ENTRY();
|
||||||
@@ -2377,7 +2376,7 @@ void scst_free_session(struct scst_session *sess)
|
|||||||
|
|
||||||
mutex_unlock(&scst_mutex);
|
mutex_unlock(&scst_mutex);
|
||||||
|
|
||||||
scst_sess_sysfs_put(sess);
|
scst_sess_sysfs_put(sess); /* must not be called under scst_mutex */
|
||||||
|
|
||||||
TRACE_EXIT();
|
TRACE_EXIT();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -468,7 +468,7 @@ out_resume_free:
|
|||||||
scst_resume_activity();
|
scst_resume_activity();
|
||||||
|
|
||||||
out_free_tgt_err:
|
out_free_tgt_err:
|
||||||
scst_tgt_sysfs_put(tgt);
|
scst_tgt_sysfs_put(tgt); /* must not be called under scst_mutex */
|
||||||
tgt = NULL;
|
tgt = NULL;
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
@@ -544,7 +544,7 @@ again:
|
|||||||
|
|
||||||
del_timer_sync(&tgt->retry_timer);
|
del_timer_sync(&tgt->retry_timer);
|
||||||
|
|
||||||
scst_tgt_sysfs_put(tgt);
|
scst_tgt_sysfs_put(tgt); /* must not be called under scst_mutex */
|
||||||
|
|
||||||
PRINT_INFO("Target %p for template %s unregistered successfully",
|
PRINT_INFO("Target %p for template %s unregistered successfully",
|
||||||
tgt, vtt->name);
|
tgt, vtt->name);
|
||||||
@@ -805,8 +805,10 @@ out_free:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
out_free_dev:
|
out_free_dev:
|
||||||
scst_device_sysfs_put(dev);
|
mutex_unlock(&scst_mutex);
|
||||||
goto out_up;
|
scst_resume_activity();
|
||||||
|
scst_device_sysfs_put(dev); /* must not be called under scst_mutex */
|
||||||
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scst_unregister_device(struct scsi_device *scsidp)
|
static void scst_unregister_device(struct scsi_device *scsidp)
|
||||||
@@ -828,7 +830,7 @@ static void scst_unregister_device(struct scsi_device *scsidp)
|
|||||||
}
|
}
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
PRINT_ERROR("%s", "Target device not found");
|
PRINT_ERROR("%s", "Target device not found");
|
||||||
goto out_unblock;
|
goto out_resume;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_del(&dev->dev_list_entry);
|
list_del(&dev->dev_list_entry);
|
||||||
@@ -844,18 +846,23 @@ static void scst_unregister_device(struct scsi_device *scsidp)
|
|||||||
put_disk(dev->rq_disk);
|
put_disk(dev->rq_disk);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
scst_device_sysfs_put(dev);
|
mutex_unlock(&scst_mutex);
|
||||||
|
scst_resume_activity();
|
||||||
|
|
||||||
|
scst_device_sysfs_put(dev); /* must not be called under scst_mutex */
|
||||||
|
|
||||||
PRINT_INFO("Detached from scsi%d, channel %d, id %d, lun %d, type %d",
|
PRINT_INFO("Detached from scsi%d, channel %d, id %d, lun %d, type %d",
|
||||||
scsidp->host->host_no, scsidp->channel, scsidp->id,
|
scsidp->host->host_no, scsidp->channel, scsidp->id,
|
||||||
scsidp->lun, scsidp->type);
|
scsidp->lun, scsidp->type);
|
||||||
|
|
||||||
out_unblock:
|
out:
|
||||||
mutex_unlock(&scst_mutex);
|
|
||||||
scst_resume_activity();
|
|
||||||
|
|
||||||
TRACE_EXIT();
|
TRACE_EXIT();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
out_resume:
|
||||||
|
mutex_unlock(&scst_mutex);
|
||||||
|
scst_resume_activity();
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scst_dev_handler_check(struct scst_dev_type *dev_handler)
|
static int scst_dev_handler_check(struct scst_dev_type *dev_handler)
|
||||||
@@ -970,8 +977,10 @@ out_free_del:
|
|||||||
list_del(&dev->dev_list_entry);
|
list_del(&dev->dev_list_entry);
|
||||||
|
|
||||||
out_release:
|
out_release:
|
||||||
scst_device_sysfs_put(dev);
|
mutex_unlock(&scst_mutex);
|
||||||
goto out_up;
|
scst_resume_activity();
|
||||||
|
scst_device_sysfs_put(dev); /* must not be called under scst_mutex */
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(scst_register_virtual_device);
|
EXPORT_SYMBOL(scst_register_virtual_device);
|
||||||
|
|
||||||
@@ -1009,12 +1018,12 @@ void scst_unregister_virtual_device(int id)
|
|||||||
PRINT_INFO("Detached from virtual device %s (id %d)",
|
PRINT_INFO("Detached from virtual device %s (id %d)",
|
||||||
dev->virt_name, dev->virt_id);
|
dev->virt_name, dev->virt_id);
|
||||||
|
|
||||||
scst_device_sysfs_put(dev);
|
|
||||||
|
|
||||||
out_unblock:
|
out_unblock:
|
||||||
mutex_unlock(&scst_mutex);
|
mutex_unlock(&scst_mutex);
|
||||||
scst_resume_activity();
|
scst_resume_activity();
|
||||||
|
|
||||||
|
scst_device_sysfs_put(dev); /* must not be called under scst_mutex */
|
||||||
|
|
||||||
TRACE_EXIT();
|
TRACE_EXIT();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -484,6 +484,10 @@ out_nomem:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must not be called under scst_mutex or there can be a deadlock with
|
||||||
|
* tgt_attr_rwsem
|
||||||
|
*/
|
||||||
void scst_tgt_sysfs_put(struct scst_tgt *tgt)
|
void scst_tgt_sysfs_put(struct scst_tgt *tgt)
|
||||||
{
|
{
|
||||||
if (tgt->tgt_kobj_initialized) {
|
if (tgt->tgt_kobj_initialized) {
|
||||||
@@ -635,10 +639,17 @@ static ssize_t scst_dev_attr_show(struct kobject *kobj, struct attribute *attr,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mutex_lock_interruptible(&dev->dev_sysfs_mutex) != 0) {
|
||||||
|
res = -EINTR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
kobj_attr = container_of(attr, struct kobj_attribute, attr);
|
kobj_attr = container_of(attr, struct kobj_attribute, attr);
|
||||||
|
|
||||||
res = kobj_attr->show(kobj, kobj_attr, buf);
|
res = kobj_attr->show(kobj, kobj_attr, buf);
|
||||||
|
|
||||||
|
mutex_unlock(&dev->dev_sysfs_mutex);
|
||||||
|
|
||||||
up_read(&dev->dev_attr_rwsem);
|
up_read(&dev->dev_attr_rwsem);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -659,10 +670,17 @@ static ssize_t scst_dev_attr_store(struct kobject *kobj, struct attribute *attr,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mutex_lock_interruptible(&dev->dev_sysfs_mutex) != 0) {
|
||||||
|
res = -EINTR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
kobj_attr = container_of(attr, struct kobj_attribute, attr);
|
kobj_attr = container_of(attr, struct kobj_attribute, attr);
|
||||||
|
|
||||||
res = kobj_attr->store(kobj, kobj_attr, buf, count);
|
res = kobj_attr->store(kobj, kobj_attr, buf, count);
|
||||||
|
|
||||||
|
mutex_unlock(&dev->dev_sysfs_mutex);
|
||||||
|
|
||||||
up_read(&dev->dev_attr_rwsem);
|
up_read(&dev->dev_attr_rwsem);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -687,6 +705,7 @@ int scst_create_device_sysfs(struct scst_device *dev)
|
|||||||
TRACE_ENTRY();
|
TRACE_ENTRY();
|
||||||
|
|
||||||
init_rwsem(&dev->dev_attr_rwsem);
|
init_rwsem(&dev->dev_attr_rwsem);
|
||||||
|
mutex_init(&dev->dev_sysfs_mutex);
|
||||||
|
|
||||||
dev->dev_kobj_initialized = 1;
|
dev->dev_kobj_initialized = 1;
|
||||||
|
|
||||||
@@ -726,6 +745,10 @@ out:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must not be called under scst_mutex or there can be a deadlock with
|
||||||
|
* dev_attr_rwsem
|
||||||
|
*/
|
||||||
void scst_device_sysfs_put(struct scst_device *dev)
|
void scst_device_sysfs_put(struct scst_device *dev)
|
||||||
{
|
{
|
||||||
TRACE_ENTRY();
|
TRACE_ENTRY();
|
||||||
@@ -937,6 +960,10 @@ out_free:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must not be called under scst_mutex or there can be a deadlock with
|
||||||
|
* sess_attr_rwsem
|
||||||
|
*/
|
||||||
void scst_sess_sysfs_put(struct scst_session *sess)
|
void scst_sess_sysfs_put(struct scst_session *sess)
|
||||||
{
|
{
|
||||||
TRACE_ENTRY();
|
TRACE_ENTRY();
|
||||||
|
|||||||
Reference in New Issue
Block a user