Patch "tpm: Replace device number bitmap with IDR" has been added to the 4.4-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
tpm: Replace device number bitmap with IDR
to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
tpm-replace-device-number-bitmap-with-idr.patch
and it can be found in the queue-4.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
15516788e581eb32ec1c50e5f00aba3faf95d817Mon Sep 17 00:00:00 2001
From: Stefan Berger <[email protected]>
Date: Mon, 29 Feb 2016 08:53:02 -0500
Subject: tpm: Replace device number bitmap with IDR
From: Stefan Berger <[email protected]>
commit 15516788e581eb32ec1c50e5f00aba3faf95d817 upstream.
Replace the device number bitmap with IDR. Extend the number of devices we can create to 64k.
Since an IDR allows us to associate a pointer with an ID, we use this now to rewrite tpm_chip_find_get() to simply look up the chip pointer by the given device ID.
Protect the IDR calls with a mutex.
--- drivers/char/tpm/tpm-chip.c | 84 ++++++++++++++++++++------------------- drivers/char/tpm/tpm-interface.c | 1 drivers/char/tpm/tpm.h | 5 -- 3 files changed, 48 insertions(+), 42 deletions(-)
drivers/char/tpm/tpm-chip.c +45 -39
@@ -29,9 +29,8 @@#include "tpm.h" #include "tpm_eventlog.h" -static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); -static LIST_HEAD (tpm_chip_list); -static DEFINE_SPINLOCK (driver_lock); +DEFINE_IDR (dev_nums_idr); +static DEFINE_MUTEX (idr_lock);struct class *tpm_class;dev_t tpm_devt;
@@ -92,20 +91,30 @@ EXPORT_SYMBOL_GPL(tpm_put_ops);*/ struct tpm_chip *tpm_chip_find_get (int chip_num) { -struct tpm_chip *pos, *chip =NULL ; +struct tpm_chip *chip, *res =NULL ; +int chip_prev; -rcu_read_lock (); -list_for_each_entry_rcu (pos, &tpm_chip_list, list) { -if (chip_num !=TPM_ANY_NUM && chip_num != pos->dev_num) -continue ; - -/* rcu prevents chip from being free'd */ -if (!tpm_try_get_ops (pos)) - chip = pos; -break ; +mutex_lock (&idr_lock); + +if (chip_num ==TPM_ANY_NUM ) { + chip_num =0 ; +do { + chip_prev = chip_num; + chip =idr_get_next (&dev_nums_idr, &chip_num); +if (chip && !tpm_try_get_ops (chip)) { + res = chip; +break ; + } + }while (chip_prev != chip_num); + }else { + chip =idr_find_slowpath (&dev_nums_idr, chip_num); +if (chip && !tpm_try_get_ops (chip)) + res = chip; } -rcu_read_unlock (); -return chip; + +mutex_unlock (&idr_lock); + +return res; }/**
@@ -118,9 +127,10 @@ static void tpm_dev_release(struct devic { struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); -spin_lock (&driver_lock); -clear_bit (chip->dev_num, dev_mask); -spin_unlock (&driver_lock); +mutex_lock (&idr_lock); +idr_remove (&dev_nums_idr, chip->dev_num); +mutex_unlock (&idr_lock); +kfree (chip); }
@@ -180,21 +190,18 @@ struct tpm_chip *tpmm_chip_alloc(structmutex_init (&chip->tpm_mutex);init_rwsem (&chip->ops_sem); -INIT_LIST_HEAD (&chip->list); chip->ops = ops; -spin_lock (&driver_lock); - chip->dev_num =find_first_zero_bit (dev_mask,TPM_NUM_DEVICES ); -spin_unlock (&driver_lock); - -if (chip->dev_num >=TPM_NUM_DEVICES ) { +mutex_lock (&idr_lock); + rc =idr_alloc (&dev_nums_idr,NULL ,0 ,TPM_NUM_DEVICES ,GFP_KERNEL ); +mutex_unlock (&idr_lock); +if (rc <0 ) {dev_err (dev,"No available tpm device numbers\n" );kfree (chip); -return ERR_PTR (-ENOMEM ); +return ERR_PTR (rc); } - -set_bit (chip->dev_num, dev_mask); + chip->dev_num = rc;scnprintf (chip->devname,sizeof (chip->devname),"tpm%d" , chip->dev_num);
@@ -252,19 +259,28 @@ static int tpm_add_char_device(struct tpreturn rc; } +/* Make the chip available. */ +mutex_lock (&idr_lock); +idr_replace (&dev_nums_idr, chip, chip->dev_num); +mutex_unlock (&idr_lock); +return rc; }static void tpm_del_char_device (struct tpm_chip *chip) {cdev_del (&chip->cdev); +device_del (&chip->dev); + +/* Make the chip unavailable. */ +mutex_lock (&idr_lock); +idr_replace (&dev_nums_idr,NULL , chip->dev_num); +mutex_unlock (&idr_lock);/* Make the driver uncallable. */ down_write (&chip->ops_sem); chip->ops =NULL ;up_write (&chip->ops_sem); - -device_del (&chip->dev); }static int tpm1_chip_register (struct tpm_chip *chip)
@@ -319,11 +335,6 @@ int tpm_chip_register(struct tpm_chip *cif (rc) goto out_err; -/* Make the chip available. */ -spin_lock (&driver_lock); -list_add_tail_rcu (&chip->list, &tpm_chip_list); -spin_unlock (&driver_lock); - chip->flags |=TPM_CHIP_FLAG_REGISTERED ;if (!(chip->flags &TPM_CHIP_FLAG_TPM2 )) {
@@ -360,11 +371,6 @@ void tpm_chip_unregister(struct tpm_chipif (!(chip->flags &TPM_CHIP_FLAG_REGISTERED ))return ; -spin_lock (&driver_lock); -list_del_rcu (&chip->list); -spin_unlock (&driver_lock); -synchronize_rcu (); -if (!(chip->flags &TPM_CHIP_FLAG_TPM2 ))sysfs_remove_link (&chip->dev.parent->kobj,"ppi" );
drivers/char/tpm/tpm-interface.c +1 -0
@@ -1127,6 +1127,7 @@ static int __init tpm_init(void) static void __exit tpm_exit(void) { +idr_destroy (&dev_nums_idr);class_destroy (tpm_class);unregister_chrdev_region (tpm_devt,TPM_NUM_DEVICES ); }
drivers/char/tpm/tpm.h +2 -3
@@ -34,7 +34,7 @@enum tpm_const {TPM_MINOR =224 ,/* officially assigned */ TPM_BUFSIZE =4096 , -TPM_NUM_DEVICES =256 , +TPM_NUM_DEVICES =65536 ,TPM_RETRY =50 ,/* 5 seconds */ };
@@ -200,8 +200,6 @@ struct tpm_chip {acpi_handle acpi_dev_handle;char ppi_version[TPM_PPI_VERSION_LEN +1 ];#endif /* CONFIG_ACPI */ - -struct list_head list; };#define to_tpm_chip (d) container_of(d, struct tpm_chip, dev)
@@ -497,6 +495,7 @@ static inline void tpm_buf_append_u32(stextern struct class *tpm_class;extern dev_t tpm_devt;extern const struct file_operations tpm_fops; +extern struct idr dev_nums_idr;enum tpm_transmit_flags {TPM_TRANSMIT_UNLOCKED =BIT (0 ),
Patches currently in stable-queue which might be from [email protected] are
queue-4.4/tpm-fix-a-kernel-memory-leak-in-tpm-sysfs.c.patch queue-4.4/tpm-replace-device-number-bitmap-with-idr.patch