From 5625a82c8aebcb9e3203e91ec83c22ae00e3fb26 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Mon, 27 Jul 2009 16:46:00 +0000 Subject: [PATCH] Merge of r972 and r977: - Fixes a race, which can lead to a hang, if a user space handler with >1 devices gets killed under load - Fix double free git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/1.0.1.x@978 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_user.c | 81 ++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index ef2b3fec8..a2c09f9dc 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -196,6 +196,7 @@ static unsigned int dev_user_poll(struct file *filp, poll_table *wait); static long dev_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static int dev_user_release(struct inode *inode, struct file *file); +static int dev_user_exit_dev(struct scst_user_dev *dev); static int dev_user_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type); @@ -2819,7 +2820,25 @@ static int dev_user_unregister_dev(struct file *file) up_read(&dev->dev_rwsem); - dev_user_release(NULL, file); + mutex_lock(&dev_priv_mutex); + dev = (struct scst_user_dev *)file->private_data; + if (dev == NULL) { + mutex_unlock(&dev_priv_mutex); + goto out; + } + + dev->blocking = 0; + wake_up_all(&dev->cmd_lists.cmd_list_waitQ); + + down_write(&dev->dev_rwsem); + file->private_data = NULL; + mutex_unlock(&dev_priv_mutex); + + dev_user_exit_dev(dev); + + up_write(&dev->dev_rwsem); /* to make lockdep happy */ + + kfree(dev); scst_resume_activity(); @@ -3051,21 +3070,10 @@ static int dev_usr_parse(struct scst_cmd *cmd) static struct scst_dev_type dev_user_devtype = USR_TYPE; -static int dev_user_release(struct inode *inode, struct file *file) +static int dev_user_exit_dev(struct scst_user_dev *dev) { - int res = 0; - struct scst_user_dev *dev; - TRACE_ENTRY(); - mutex_lock(&dev_priv_mutex); - dev = (struct scst_user_dev *)file->private_data; - if (dev == NULL) { - mutex_unlock(&dev_priv_mutex); - goto out; - } - file->private_data = NULL; - TRACE(TRACE_MGMT, "Releasing dev %s", dev->name); spin_lock(&dev_list_lock); @@ -3075,9 +3083,6 @@ static int dev_user_release(struct inode *inode, struct file *file) dev->blocking = 0; wake_up_all(&dev->cmd_lists.cmd_list_waitQ); - down_write(&dev->dev_rwsem); - mutex_unlock(&dev_priv_mutex); - spin_lock(&cleanup_lock); list_add_tail(&dev->cleanup_list_entry, &cleanup_list); spin_unlock(&cleanup_lock); @@ -3102,17 +3107,49 @@ static int dev_user_release(struct inode *inode, struct file *file) sgv_pool_destroy(dev->pool_clust); sgv_pool_destroy(dev->pool); - up_write(&dev->dev_rwsem); /* to make lockdep happy */ - TRACE_MGMT_DBG("Releasing completed (dev %p)", dev); - kfree(dev); - module_put(THIS_MODULE); + TRACE_EXIT(); + return 0; +} + +static int __dev_user_release(void *arg) +{ + struct scst_user_dev *dev = (struct scst_user_dev *)arg; + dev_user_exit_dev(dev); + kfree(dev); + return 0; +} + +static int dev_user_release(struct inode *inode, struct file *file) +{ + struct scst_user_dev *dev; + struct task_struct *t; + + TRACE_ENTRY(); + + dev = (struct scst_user_dev *)file->private_data; + if (dev == NULL) { + mutex_unlock(&dev_priv_mutex); + goto out; + } + file->private_data = NULL; + + TRACE_MGMT_DBG("Going to release dev %s", dev->name); + + t = kthread_run(__dev_user_release, dev, "scst_usr_released"); + if (IS_ERR(t)) { + PRINT_CRIT_ERROR("kthread_run() failed (%ld), releasing device " + "%p directly. If you have several devices under load " + "it might deadlock!", PTR_ERR(t), dev); + __dev_user_release(dev); + } + out: - TRACE_EXIT_RES(res); - return res; + TRACE_EXIT(); + return 0; } static int dev_user_process_cleanup(struct scst_user_dev *dev)