aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2014-12-23 00:40:18 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2014-12-25 16:33:34 -0500
commit15b66cd54291186011f733cc750263f320b8a0a4 (patch)
tree3b95b884c9381f5fb6a7ea4286df2288d61ba4ac
parent77584ee57434813b50fc85cde995a6271a5081b7 (diff)
hwrng: core - Fix current_rng init/cleanup race yet again
The kref solution is still buggy because we were only focusing on the register/unregister race. The same race affects the setting of current_rng through sysfs. This patch fixes it by using kref_get_unless_zero. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--drivers/char/hw_random/core.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 3dba2cf50241..42827fd5f38d 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -105,7 +105,6 @@ static inline void cleanup_rng(struct kref *kref)
105static void set_current_rng(struct hwrng *rng) 105static void set_current_rng(struct hwrng *rng)
106{ 106{
107 BUG_ON(!mutex_is_locked(&rng_mutex)); 107 BUG_ON(!mutex_is_locked(&rng_mutex));
108 kref_get(&rng->ref);
109 current_rng = rng; 108 current_rng = rng;
110} 109}
111 110
@@ -150,6 +149,9 @@ static void put_rng(struct hwrng *rng)
150 149
151static inline int hwrng_init(struct hwrng *rng) 150static inline int hwrng_init(struct hwrng *rng)
152{ 151{
152 if (kref_get_unless_zero(&rng->ref))
153 goto skip_init;
154
153 if (rng->init) { 155 if (rng->init) {
154 int ret; 156 int ret;
155 157
@@ -157,6 +159,11 @@ static inline int hwrng_init(struct hwrng *rng)
157 if (ret) 159 if (ret)
158 return ret; 160 return ret;
159 } 161 }
162
163 kref_init(&rng->ref);
164 reinit_completion(&rng->cleanup_done);
165
166skip_init:
160 add_early_randomness(rng); 167 add_early_randomness(rng);
161 168
162 current_quality = rng->quality ? : default_quality; 169 current_quality = rng->quality ? : default_quality;
@@ -467,6 +474,9 @@ int hwrng_register(struct hwrng *rng)
467 goto out_unlock; 474 goto out_unlock;
468 } 475 }
469 476
477 init_completion(&rng->cleanup_done);
478 complete(&rng->cleanup_done);
479
470 old_rng = current_rng; 480 old_rng = current_rng;
471 err = 0; 481 err = 0;
472 if (!old_rng) { 482 if (!old_rng) {
@@ -494,8 +504,6 @@ int hwrng_register(struct hwrng *rng)
494 add_early_randomness(rng); 504 add_early_randomness(rng);
495 } 505 }
496 506
497 init_completion(&rng->cleanup_done);
498
499out_unlock: 507out_unlock:
500 mutex_unlock(&rng_mutex); 508 mutex_unlock(&rng_mutex);
501out: 509out: