diff options
author | Jason Gunthorpe <jgunthorpe@obsidianresearch.com> | 2016-02-13 04:29:53 +0100 |
---|---|---|
committer | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> | 2016-06-25 16:26:35 +0200 |
commit | 4e26195f240d73150e8308ae42874702e3df8d2c (patch) | |
tree | c0e8ff3604b09484393d10a927ed1e9a46a7ed0d /drivers/char/tpm/tpm.h | |
parent | tpm: Get rid of devname (diff) | |
download | linux-4e26195f240d73150e8308ae42874702e3df8d2c.tar.xz 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 '')
-rw-r--r-- | drivers/char/tpm/tpm.h | 14 |
1 files changed, 9 insertions, 5 deletions
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 5d33ba595929..c6376b174fbe 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -170,7 +170,13 @@ struct tpm_chip { struct device dev; struct cdev cdev; + /* A driver callback under ops cannot be run unless ops_sem is held + * (sometimes implicitly, eg for the sysfs code). ops becomes null + * when the driver is unregistered, see tpm_try_get_ops. + */ + struct rw_semaphore ops_sem; const struct tpm_class_ops *ops; + unsigned int flags; int dev_num; /* /dev/tpm# */ @@ -195,11 +201,6 @@ struct tpm_chip { #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) -static inline void tpm_chip_put(struct tpm_chip *chip) -{ - module_put(chip->dev.parent->driver->owner); -} - static inline int tpm_read_index(int base, int index) { outb(index, base); @@ -507,6 +508,9 @@ extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, wait_queue_head_t *, bool); struct tpm_chip *tpm_chip_find_get(int chip_num); +__must_check int tpm_try_get_ops(struct tpm_chip *chip); +void tpm_put_ops(struct tpm_chip *chip); + extern struct tpm_chip *tpmm_chip_alloc(struct device *dev, const struct tpm_class_ops *ops); extern int tpm_chip_register(struct tpm_chip *chip); |