@@ -51,23 +51,44 @@ static void timeout_work(struct work_struct *work)
mutex_unlock(&priv->buffer_mutex);
}
+static int tpm_open_lock(struct tpm_chip *chip, int lock)
+{
+ static DECLARE_COMPLETION(wait);
+
+ if (lock) {
+ while (test_and_set_bit(0, &chip->is_open)) {
+ int ret;
+
+ dev_dbg(&chip->dev, "Another process owns this TPM\n");
+ ret = wait_for_completion_interruptible(&wait);
+ if (ret)
+ return ret;
+ }
+ } else {
+ clear_bit(0, &chip->is_open);
+ complete(&wait);
+ }
+
+ return 0;
+}
+
static int tpm_open(struct inode *inode, struct file *file)
{
struct tpm_chip *chip =
container_of(inode->i_cdev, struct tpm_chip, cdev);
struct file_priv *priv;
+ int ret;
/* It's assured that the chip will be opened just once,
* by the check of is_open variable, which is protected
* by driver_lock. */
- if (test_and_set_bit(0, &chip->is_open)) {
- dev_dbg(&chip->dev, "Another process owns this TPM\n");
- return -EBUSY;
- }
+ ret = tpm_open_lock(chip, 1);
+ if (ret)
+ return ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (priv == NULL) {
- clear_bit(0, &chip->is_open);
+ tpm_open_lock(chip, 0);
return -ENOMEM;
}
@@ -173,7 +194,7 @@ static int tpm_release(struct inode *inode, struct file *file)
flush_work(&priv->work);
file->private_data = NULL;
atomic_set(&priv->data_pending, 0);
- clear_bit(0, &priv->chip->is_open);
+ tpm_open_lock(priv->chip, 0);
kfree(priv);
return 0;
}