/* 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
/* 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.
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
/*
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;
*
* 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)
{
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");
PRINT_ERROR("File path \"%s\" is not "
"absolute", file_name);
res = -EINVAL;
- goto out_resume;
+ goto out_unlock;
} else
virt_dev->cdrom_empty = 0;
TRACE(TRACE_OUT_OF_MEM, "%s",
"Allocation of file_name failed");
res = -ENOMEM;
- goto out_resume;
+ goto out_unlock;
}
strncpy(fn, file_name, len);
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) {
out_free:
kfree(virt_dev->file_name);
virt_dev->file_name = old_fn;
+
+out_unlock:
+ mutex_unlock(&scst_mutex);
goto out_resume;
}
* flush_scheduled_work().
*/
struct mutex scst_mutex;
+EXPORT_SYMBOL(scst_mutex);
/* All 3 protected by scst_mutex */
struct list_head scst_template_list;
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");
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;
{
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);
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);
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
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);