Commit b6c96c0214138186f495e3ee73737c6fc5e4efa2
Committed by
Rusty Russell
1 parent
07fe9977b6
Exists in
master
and in
38 other branches
lguest: Make sure interrupt is allocated ok by lguest_setup_irq
Make sure the interrupt is allocated correctly by lguest_setup_irq (check the return value of irq_alloc_desc_at for -ENOMEM) Signed-off-by: Stratos Psomadakis <psomas@cslab.ece.ntua.gr> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (cleanups and commentry)
Showing 2 changed files with 20 additions and 11 deletions Side-by-side Diff
arch/x86/lguest/boot.c
... | ... | @@ -856,18 +856,23 @@ |
856 | 856 | } |
857 | 857 | |
858 | 858 | /* |
859 | - * With CONFIG_SPARSE_IRQ, interrupt descriptors are allocated as-needed, so | |
860 | - * rather than set them in lguest_init_IRQ we are called here every time an | |
861 | - * lguest device needs an interrupt. | |
862 | - * | |
863 | - * FIXME: irq_alloc_desc_at() can fail due to lack of memory, we should | |
864 | - * pass that up! | |
859 | + * Interrupt descriptors are allocated as-needed, but low-numbered ones are | |
860 | + * reserved by the generic x86 code. So we ignore irq_alloc_desc_at if it | |
861 | + * tells us the irq is already used: other errors (ie. ENOMEM) we take | |
862 | + * seriously. | |
865 | 863 | */ |
866 | -void lguest_setup_irq(unsigned int irq) | |
864 | +int lguest_setup_irq(unsigned int irq) | |
867 | 865 | { |
868 | - irq_alloc_desc_at(irq, 0); | |
866 | + int err; | |
867 | + | |
868 | + /* Returns -ve error or vector number. */ | |
869 | + err = irq_alloc_desc_at(irq, 0); | |
870 | + if (err < 0 && err != -EEXIST) | |
871 | + return err; | |
872 | + | |
869 | 873 | irq_set_chip_and_handler_name(irq, &lguest_irq_controller, |
870 | 874 | handle_level_irq, "level"); |
875 | + return 0; | |
871 | 876 | } |
872 | 877 | |
873 | 878 | /* |
drivers/lguest/lguest_device.c
... | ... | @@ -241,7 +241,7 @@ |
241 | 241 | } |
242 | 242 | |
243 | 243 | /* An extern declaration inside a C file is bad form. Don't do it. */ |
244 | -extern void lguest_setup_irq(unsigned int irq); | |
244 | +extern int lguest_setup_irq(unsigned int irq); | |
245 | 245 | |
246 | 246 | /* |
247 | 247 | * This routine finds the Nth virtqueue described in the configuration of |
... | ... | @@ -304,7 +304,9 @@ |
304 | 304 | } |
305 | 305 | |
306 | 306 | /* Make sure the interrupt is allocated. */ |
307 | - lguest_setup_irq(lvq->config.irq); | |
307 | + err = lguest_setup_irq(lvq->config.irq); | |
308 | + if (err) | |
309 | + goto destroy_vring; | |
308 | 310 | |
309 | 311 | /* |
310 | 312 | * Tell the interrupt for this virtqueue to go to the virtio_ring |
... | ... | @@ -317,7 +319,7 @@ |
317 | 319 | err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED, |
318 | 320 | dev_name(&vdev->dev), vq); |
319 | 321 | if (err) |
320 | - goto destroy_vring; | |
322 | + goto free_desc; | |
321 | 323 | |
322 | 324 | /* |
323 | 325 | * Last of all we hook up our 'struct lguest_vq_info" to the |
... | ... | @@ -326,6 +328,8 @@ |
326 | 328 | vq->priv = lvq; |
327 | 329 | return vq; |
328 | 330 | |
331 | +free_desc: | |
332 | + irq_free_desc(lvq->config.irq); | |
329 | 333 | destroy_vring: |
330 | 334 | vring_del_virtqueue(vq); |
331 | 335 | unmap: |