diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-07-19 02:25:54 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-07-19 02:25:54 -0400 |
| commit | 4e106275290bdb015bc16dc48e55d78cc480e7c7 (patch) | |
| tree | 0fe35ef231b8219883230e6a39a193ea57ac5418 | |
| parent | f83971912231fe5390d2357442b6c25bb8076d9b (diff) | |
| parent | e052dbf554610e2104c5a7518c4d8374bed701bb (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto fixes from Herbert Xu:
"This push fixes a boot hang in virt guests when the virtio RNG is
enabled"
* git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6:
hwrng: virtio - ensure reads happen after successful probe
hwrng: fetch randomness only after device init
| -rw-r--r-- | drivers/char/hw_random/core.c | 47 | ||||
| -rw-r--r-- | drivers/char/hw_random/virtio-rng.c | 10 |
2 files changed, 49 insertions, 8 deletions
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 334601cc81cf..c4419ea1ab07 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c | |||
| @@ -55,16 +55,41 @@ static DEFINE_MUTEX(rng_mutex); | |||
| 55 | static int data_avail; | 55 | static int data_avail; |
| 56 | static u8 *rng_buffer; | 56 | static u8 *rng_buffer; |
| 57 | 57 | ||
| 58 | static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, | ||
| 59 | int wait); | ||
| 60 | |||
| 58 | static size_t rng_buffer_size(void) | 61 | static size_t rng_buffer_size(void) |
| 59 | { | 62 | { |
| 60 | return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; | 63 | return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; |
| 61 | } | 64 | } |
| 62 | 65 | ||
| 66 | static void add_early_randomness(struct hwrng *rng) | ||
| 67 | { | ||
| 68 | unsigned char bytes[16]; | ||
| 69 | int bytes_read; | ||
| 70 | |||
| 71 | /* | ||
| 72 | * Currently only virtio-rng cannot return data during device | ||
| 73 | * probe, and that's handled in virtio-rng.c itself. If there | ||
| 74 | * are more such devices, this call to rng_get_data can be | ||
| 75 | * made conditional here instead of doing it per-device. | ||
| 76 | */ | ||
| 77 | bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1); | ||
| 78 | if (bytes_read > 0) | ||
| 79 | add_device_randomness(bytes, bytes_read); | ||
| 80 | } | ||
| 81 | |||
| 63 | static inline int hwrng_init(struct hwrng *rng) | 82 | static inline int hwrng_init(struct hwrng *rng) |
| 64 | { | 83 | { |
| 65 | if (!rng->init) | 84 | if (rng->init) { |
| 66 | return 0; | 85 | int ret; |
| 67 | return rng->init(rng); | 86 | |
| 87 | ret = rng->init(rng); | ||
| 88 | if (ret) | ||
| 89 | return ret; | ||
| 90 | } | ||
| 91 | add_early_randomness(rng); | ||
| 92 | return 0; | ||
| 68 | } | 93 | } |
| 69 | 94 | ||
| 70 | static inline void hwrng_cleanup(struct hwrng *rng) | 95 | static inline void hwrng_cleanup(struct hwrng *rng) |
| @@ -304,8 +329,6 @@ int hwrng_register(struct hwrng *rng) | |||
| 304 | { | 329 | { |
| 305 | int err = -EINVAL; | 330 | int err = -EINVAL; |
| 306 | struct hwrng *old_rng, *tmp; | 331 | struct hwrng *old_rng, *tmp; |
| 307 | unsigned char bytes[16]; | ||
| 308 | int bytes_read; | ||
| 309 | 332 | ||
| 310 | if (rng->name == NULL || | 333 | if (rng->name == NULL || |
| 311 | (rng->data_read == NULL && rng->read == NULL)) | 334 | (rng->data_read == NULL && rng->read == NULL)) |
| @@ -347,9 +370,17 @@ int hwrng_register(struct hwrng *rng) | |||
| 347 | INIT_LIST_HEAD(&rng->list); | 370 | INIT_LIST_HEAD(&rng->list); |
| 348 | list_add_tail(&rng->list, &rng_list); | 371 | list_add_tail(&rng->list, &rng_list); |
| 349 | 372 | ||
| 350 | bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1); | 373 | if (old_rng && !rng->init) { |
| 351 | if (bytes_read > 0) | 374 | /* |
| 352 | add_device_randomness(bytes, bytes_read); | 375 | * Use a new device's input to add some randomness to |
| 376 | * the system. If this rng device isn't going to be | ||
| 377 | * used right away, its init function hasn't been | ||
| 378 | * called yet; so only use the randomness from devices | ||
| 379 | * that don't need an init callback. | ||
| 380 | */ | ||
| 381 | add_early_randomness(rng); | ||
| 382 | } | ||
| 383 | |||
| 353 | out_unlock: | 384 | out_unlock: |
| 354 | mutex_unlock(&rng_mutex); | 385 | mutex_unlock(&rng_mutex); |
| 355 | out: | 386 | out: |
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index f3e71501de54..e9b15bc18b4d 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c | |||
| @@ -38,6 +38,8 @@ struct virtrng_info { | |||
| 38 | int index; | 38 | int index; |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | static bool probe_done; | ||
| 42 | |||
| 41 | static void random_recv_done(struct virtqueue *vq) | 43 | static void random_recv_done(struct virtqueue *vq) |
| 42 | { | 44 | { |
| 43 | struct virtrng_info *vi = vq->vdev->priv; | 45 | struct virtrng_info *vi = vq->vdev->priv; |
| @@ -67,6 +69,13 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait) | |||
| 67 | int ret; | 69 | int ret; |
| 68 | struct virtrng_info *vi = (struct virtrng_info *)rng->priv; | 70 | struct virtrng_info *vi = (struct virtrng_info *)rng->priv; |
| 69 | 71 | ||
| 72 | /* | ||
| 73 | * Don't ask host for data till we're setup. This call can | ||
| 74 | * happen during hwrng_register(), after commit d9e7972619. | ||
| 75 | */ | ||
| 76 | if (unlikely(!probe_done)) | ||
| 77 | return 0; | ||
| 78 | |||
| 70 | if (!vi->busy) { | 79 | if (!vi->busy) { |
| 71 | vi->busy = true; | 80 | vi->busy = true; |
| 72 | init_completion(&vi->have_data); | 81 | init_completion(&vi->have_data); |
| @@ -137,6 +146,7 @@ static int probe_common(struct virtio_device *vdev) | |||
| 137 | return err; | 146 | return err; |
| 138 | } | 147 | } |
| 139 | 148 | ||
| 149 | probe_done = true; | ||
| 140 | return 0; | 150 | return 0; |
| 141 | } | 151 | } |
| 142 | 152 | ||
