diff options
author | Jason Gunthorpe | 2016-02-13 04:29:53 +0100 |
---|---|---|
committer | Jarkko Sakkinen | 2016-06-25 16:26:35 +0200 |
commit | 4e26195f240d73150e8308ae42874702e3df8d2c (patch) | |
tree | c0e8ff3604b09484393d10a927ed1e9a46a7ed0d /drivers/char/tpm/tpm-dev.c | |
parent | tpm: Get rid of devname (diff) | |
download | kernel-qcow2-linux-4e26195f240d73150e8308ae42874702e3df8d2c.tar.gz kernel-qcow2-linux-4e26195f240d73150e8308ae42874702e3df8d2c.tar.xz kernel-qcow2-linux-4e26195f240d73150e8308ae42874702e3df8d2c.zip |
tpm: Provide strong locking for device removal
Add a read/write semaphore around the ops function pointers so
ops can be set to null when the driver un-registers.
Previously the tpm core expected module locking to be enough to
ensure that tpm_unregister could not be called during certain times,
however that hasn't been sufficient for a long time.
Introduce a read/write semaphore around 'ops' so the core can set
it to null when unregistering. This provides a strong fence around
the driver callbacks, guaranteeing to the driver that no callbacks
are running or will run again.
For now the ops_lock is placed very high in the call stack, it could
be pushed down and made more granular in future if necessary.
Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Diffstat (limited to 'drivers/char/tpm/tpm-dev.c')
-rw-r--r-- | drivers/char/tpm/tpm-dev.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index 4009765c14fd..f5d452151c6b 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -136,9 +136,18 @@ static ssize_t tpm_write(struct file *file, const char __user *buf, return -EFAULT; } - /* atomic tpm command send and result receive */ + /* atomic tpm command send and result receive. We only hold the ops + * lock during this period so that the tpm can be unregistered even if + * the char dev is held open. + */ + if (tpm_try_get_ops(priv->chip)) { + mutex_unlock(&priv->buffer_mutex); + return -EPIPE; + } out_size = tpm_transmit(priv->chip, priv->data_buffer, sizeof(priv->data_buffer)); + + tpm_put_ops(priv->chip); if (out_size < 0) { mutex_unlock(&priv->buffer_mutex); return out_size; |