From 1de649c2633659343b43a257fd7c6cdd102726db Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 27 Nov 2009 18:22:45 +0000 Subject: [PATCH] Followup for r1361 git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1364 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/scst.h | 14 +++++++++++++- scst/src/dev_handlers/scst_vdisk.c | 18 ++++++++++++++---- scst/src/scst_main.c | 3 +++ scst/src/scst_priv.h | 3 ++- scst/src/scst_sysfs.c | 17 ++++++++++++++++- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index 3785ac94f..a0558bcc1 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1063,7 +1063,10 @@ struct scst_dev_type { /* Optional sysfs attributes */ const struct attribute **devt_attrs; - /* Optional sysfs device attributes */ + /* + * Optional sysfs device attributes. They are serialized + * by dev_sysfs_mutex. + */ const struct attribute **dev_attrs; #endif @@ -1145,6 +1148,9 @@ struct scst_tgt { /* Set if tgt_kobj was initialized */ unsigned int tgt_kobj_initialized:1; + /* Set if scst_tgt_sysfs_prepare_put() was called for tgt_kobj */ + unsigned int tgt_kobj_put_prepared:1; + /* * Used to protect sysfs attributes to be called after this * object was unregistered. @@ -3218,6 +3224,12 @@ struct scst_trace_log { const char *token; }; +/* + * Main SCST mutex. All targets, devices and dev_types management is done + * under this mutex. + */ +extern struct mutex scst_mutex; + #ifdef CONFIG_SCST_PROC /* diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 15ac6f773..7fcf4a6c7 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -212,7 +212,8 @@ struct scst_vdisk_dev { int virt_id; char name[16+1]; /* Name of the virtual device, must be <= SCSI Model + 1 */ - char *file_name; /* File name */ + char *file_name; /* File name, protected by + scst_mutex and suspended activities */ char usn[MAX_USN_LEN]; struct scst_device *dev; struct list_head vdisk_dev_list_entry; @@ -815,7 +816,8 @@ out: * * Returns : None * - * Description: Called to detach this device type driver + * Description: Called to detach this device type driver. + * Scst_mutex supposed to be held. ************************************************************/ static void vdisk_detach(struct scst_device *dev) { @@ -3457,6 +3459,9 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, if (res != 0) goto out; + /* To sync with detach*() functions */ + mutex_lock(&scst_mutex); + if (*file_name == '\0') { virt_dev->cdrom_empty = 1; TRACE_DBG("%s", "No media"); @@ -3464,7 +3469,7 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, PRINT_ERROR("File path \"%s\" is not " "absolute", file_name); res = -EINVAL; - goto out_resume; + goto out_unlock; } else virt_dev->cdrom_empty = 0; @@ -3477,7 +3482,7 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of file_name failed"); res = -ENOMEM; - goto out_resume; + goto out_unlock; } strncpy(fn, file_name, len); @@ -3504,6 +3509,8 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev, if (!virt_dev->cdrom_empty) virt_dev->media_changed = 1; + mutex_unlock(&scst_mutex); + scst_dev_del_all_thr_data(virt_dev->dev); if (!virt_dev->cdrom_empty) { @@ -3532,6 +3539,9 @@ out: out_free: kfree(virt_dev->file_name); virt_dev->file_name = old_fn; + +out_unlock: + mutex_unlock(&scst_mutex); goto out_resume; } diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 02b857617..f647b50fa 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -79,6 +79,7 @@ * flush_scheduled_work(). */ struct mutex scst_mutex; +EXPORT_SYMBOL(scst_mutex); /* All 3 protected by scst_mutex */ struct list_head scst_template_list; @@ -494,6 +495,8 @@ void scst_unregister(struct scst_tgt *tgt) TRACE_ENTRY(); + scst_tgt_sysfs_prepare_put(tgt); + TRACE_DBG("%s", "Calling target driver's release()"); tgt->tgtt->release(tgt); TRACE_DBG("%s", "Target driver's release() returned"); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index d2bd953ea..0c3ff6a96 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -144,7 +144,6 @@ extern spinlock_t scst_main_lock; extern struct scst_sgv_pools scst_sgv; extern unsigned long scst_flags; -extern struct mutex scst_mutex; extern atomic_t scst_cmd_count; extern struct list_head scst_template_list; extern struct list_head scst_dev_list; @@ -443,6 +442,7 @@ static inline int scst_create_tgt_sysfs(struct scst_tgt *tgt) { return 0; } +static inline void scst_tgt_sysfs_prepare_put(struct scst_tgt *tgt) { } static inline void scst_tgt_sysfs_put(struct scst_tgt *tgt) { scst_free_tgt(tgt); @@ -497,6 +497,7 @@ void scst_sysfs_cleanup(void); int scst_create_tgtt_sysfs(struct scst_tgt_template *tgtt); void scst_tgtt_sysfs_put(struct scst_tgt_template *tgtt); int scst_create_tgt_sysfs(struct scst_tgt *tgt); +void scst_tgt_sysfs_prepare_put(struct scst_tgt *tgt); void scst_tgt_sysfs_put(struct scst_tgt *tgt); int scst_create_sess_sysfs(struct scst_session *sess); void scst_sess_sysfs_put(struct scst_session *sess); diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 85c17408e..310729e98 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -484,6 +484,20 @@ out_nomem: goto out; } +/* + * Must not be called under scst_mutex or there can be a deadlock with + * tgt_attr_rwsem + */ +void scst_tgt_sysfs_prepare_put(struct scst_tgt *tgt) +{ + if (tgt->tgt_kobj_initialized) { + down_write(&tgt->tgt_attr_rwsem); + tgt->tgt_kobj_put_prepared = 1; + } + + return; +} + /* * Must not be called under scst_mutex or there can be a deadlock with * tgt_attr_rwsem @@ -504,7 +518,8 @@ void scst_tgt_sysfs_put(struct scst_tgt *tgt) kobject_del(&tgt->tgt_kobj); - down_write(&tgt->tgt_attr_rwsem); + if (!tgt->tgt_kobj_put_prepared) + down_write(&tgt->tgt_attr_rwsem); kobject_put(&tgt->tgt_kobj); } else scst_free_tgt(tgt);