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>
static void set_current_rng(struct hwrng *rng)
{
BUG_ON(!mutex_is_locked(&rng_mutex));
- kref_get(&rng->ref);
current_rng = rng;
}
static inline int hwrng_init(struct hwrng *rng)
{
+ if (kref_get_unless_zero(&rng->ref))
+ goto skip_init;
+
if (rng->init) {
int ret;
if (ret)
return ret;
}
+
+ kref_init(&rng->ref);
+ reinit_completion(&rng->cleanup_done);
+
+skip_init:
add_early_randomness(rng);
current_quality = rng->quality ? : default_quality;
goto out_unlock;
}
+ init_completion(&rng->cleanup_done);
+ complete(&rng->cleanup_done);
+
old_rng = current_rng;
err = 0;
if (!old_rng) {
add_early_randomness(rng);
}
- init_completion(&rng->cleanup_done);
-
out_unlock:
mutex_unlock(&rng_mutex);
out: