diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2017-11-14 13:11:21 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-11-14 13:11:21 -0500 |
commit | 1a03bac30341dcf98c0d7d181c52edcff7e248c5 (patch) | |
tree | 60eeeb67e254c425892acfcd7c37d6ba4ed2d352 | |
parent | 9c42da50c068bd3f54cd6248efd9c92d118918ed (diff) | |
parent | b7636e816adcb52bc96b6fb7bc9d141cbfd17ddb (diff) |
Merge branch 'pci/endpoint' into next
* pci/endpoint:
misc: pci_endpoint_test: Fix BUG_ON error during pci_disable_msi()
misc: pci_endpoint_test: Fix pci_endpoint_test not releasing resources on remove
misc: pci_endpoint_test: Fix failure path return values in probe
misc: pci_endpoint_test: Avoid triggering a BUG()
misc: pci_endpoint_test: Prevent some integer overflows
-rw-r--r-- | drivers/misc/pci_endpoint_test.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index deb203026496..320276f42653 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c | |||
@@ -92,6 +92,7 @@ struct pci_endpoint_test { | |||
92 | void __iomem *bar[6]; | 92 | void __iomem *bar[6]; |
93 | struct completion irq_raised; | 93 | struct completion irq_raised; |
94 | int last_irq; | 94 | int last_irq; |
95 | int num_irqs; | ||
95 | /* mutex to protect the ioctls */ | 96 | /* mutex to protect the ioctls */ |
96 | struct mutex mutex; | 97 | struct mutex mutex; |
97 | struct miscdevice miscdev; | 98 | struct miscdevice miscdev; |
@@ -226,6 +227,9 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) | |||
226 | u32 src_crc32; | 227 | u32 src_crc32; |
227 | u32 dst_crc32; | 228 | u32 dst_crc32; |
228 | 229 | ||
230 | if (size > SIZE_MAX - alignment) | ||
231 | goto err; | ||
232 | |||
229 | orig_src_addr = dma_alloc_coherent(dev, size + alignment, | 233 | orig_src_addr = dma_alloc_coherent(dev, size + alignment, |
230 | &orig_src_phys_addr, GFP_KERNEL); | 234 | &orig_src_phys_addr, GFP_KERNEL); |
231 | if (!orig_src_addr) { | 235 | if (!orig_src_addr) { |
@@ -311,6 +315,9 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) | |||
311 | size_t alignment = test->alignment; | 315 | size_t alignment = test->alignment; |
312 | u32 crc32; | 316 | u32 crc32; |
313 | 317 | ||
318 | if (size > SIZE_MAX - alignment) | ||
319 | goto err; | ||
320 | |||
314 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, | 321 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, |
315 | GFP_KERNEL); | 322 | GFP_KERNEL); |
316 | if (!orig_addr) { | 323 | if (!orig_addr) { |
@@ -369,6 +376,9 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) | |||
369 | size_t alignment = test->alignment; | 376 | size_t alignment = test->alignment; |
370 | u32 crc32; | 377 | u32 crc32; |
371 | 378 | ||
379 | if (size > SIZE_MAX - alignment) | ||
380 | goto err; | ||
381 | |||
372 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, | 382 | orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, |
373 | GFP_KERNEL); | 383 | GFP_KERNEL); |
374 | if (!orig_addr) { | 384 | if (!orig_addr) { |
@@ -504,6 +514,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
504 | irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); | 514 | irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); |
505 | if (irq < 0) | 515 | if (irq < 0) |
506 | dev_err(dev, "failed to get MSI interrupts\n"); | 516 | dev_err(dev, "failed to get MSI interrupts\n"); |
517 | test->num_irqs = irq; | ||
507 | } | 518 | } |
508 | 519 | ||
509 | err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, | 520 | err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler, |
@@ -533,6 +544,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
533 | 544 | ||
534 | test->base = test->bar[test_reg_bar]; | 545 | test->base = test->bar[test_reg_bar]; |
535 | if (!test->base) { | 546 | if (!test->base) { |
547 | err = -ENOMEM; | ||
536 | dev_err(dev, "Cannot perform PCI test without BAR%d\n", | 548 | dev_err(dev, "Cannot perform PCI test without BAR%d\n", |
537 | test_reg_bar); | 549 | test_reg_bar); |
538 | goto err_iounmap; | 550 | goto err_iounmap; |
@@ -542,6 +554,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
542 | 554 | ||
543 | id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL); | 555 | id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL); |
544 | if (id < 0) { | 556 | if (id < 0) { |
557 | err = id; | ||
545 | dev_err(dev, "unable to get id\n"); | 558 | dev_err(dev, "unable to get id\n"); |
546 | goto err_iounmap; | 559 | goto err_iounmap; |
547 | } | 560 | } |
@@ -549,17 +562,24 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, | |||
549 | snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id); | 562 | snprintf(name, sizeof(name), DRV_MODULE_NAME ".%d", id); |
550 | misc_device = &test->miscdev; | 563 | misc_device = &test->miscdev; |
551 | misc_device->minor = MISC_DYNAMIC_MINOR; | 564 | misc_device->minor = MISC_DYNAMIC_MINOR; |
552 | misc_device->name = name; | 565 | misc_device->name = kstrdup(name, GFP_KERNEL); |
566 | if (!misc_device->name) { | ||
567 | err = -ENOMEM; | ||
568 | goto err_ida_remove; | ||
569 | } | ||
553 | misc_device->fops = &pci_endpoint_test_fops, | 570 | misc_device->fops = &pci_endpoint_test_fops, |
554 | 571 | ||
555 | err = misc_register(misc_device); | 572 | err = misc_register(misc_device); |
556 | if (err) { | 573 | if (err) { |
557 | dev_err(dev, "failed to register device\n"); | 574 | dev_err(dev, "failed to register device\n"); |
558 | goto err_ida_remove; | 575 | goto err_kfree_name; |
559 | } | 576 | } |
560 | 577 | ||
561 | return 0; | 578 | return 0; |
562 | 579 | ||
580 | err_kfree_name: | ||
581 | kfree(misc_device->name); | ||
582 | |||
563 | err_ida_remove: | 583 | err_ida_remove: |
564 | ida_simple_remove(&pci_endpoint_test_ida, id); | 584 | ida_simple_remove(&pci_endpoint_test_ida, id); |
565 | 585 | ||
@@ -569,6 +589,9 @@ err_iounmap: | |||
569 | pci_iounmap(pdev, test->bar[bar]); | 589 | pci_iounmap(pdev, test->bar[bar]); |
570 | } | 590 | } |
571 | 591 | ||
592 | for (i = 0; i < irq; i++) | ||
593 | devm_free_irq(dev, pdev->irq + i, test); | ||
594 | |||
572 | err_disable_msi: | 595 | err_disable_msi: |
573 | pci_disable_msi(pdev); | 596 | pci_disable_msi(pdev); |
574 | pci_release_regions(pdev); | 597 | pci_release_regions(pdev); |
@@ -582,19 +605,25 @@ err_disable_pdev: | |||
582 | static void pci_endpoint_test_remove(struct pci_dev *pdev) | 605 | static void pci_endpoint_test_remove(struct pci_dev *pdev) |
583 | { | 606 | { |
584 | int id; | 607 | int id; |
608 | int i; | ||
585 | enum pci_barno bar; | 609 | enum pci_barno bar; |
586 | struct pci_endpoint_test *test = pci_get_drvdata(pdev); | 610 | struct pci_endpoint_test *test = pci_get_drvdata(pdev); |
587 | struct miscdevice *misc_device = &test->miscdev; | 611 | struct miscdevice *misc_device = &test->miscdev; |
588 | 612 | ||
589 | if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1) | 613 | if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1) |
590 | return; | 614 | return; |
615 | if (id < 0) | ||
616 | return; | ||
591 | 617 | ||
592 | misc_deregister(&test->miscdev); | 618 | misc_deregister(&test->miscdev); |
619 | kfree(misc_device->name); | ||
593 | ida_simple_remove(&pci_endpoint_test_ida, id); | 620 | ida_simple_remove(&pci_endpoint_test_ida, id); |
594 | for (bar = BAR_0; bar <= BAR_5; bar++) { | 621 | for (bar = BAR_0; bar <= BAR_5; bar++) { |
595 | if (test->bar[bar]) | 622 | if (test->bar[bar]) |
596 | pci_iounmap(pdev, test->bar[bar]); | 623 | pci_iounmap(pdev, test->bar[bar]); |
597 | } | 624 | } |
625 | for (i = 0; i < test->num_irqs; i++) | ||
626 | devm_free_irq(&pdev->dev, pdev->irq + i, test); | ||
598 | pci_disable_msi(pdev); | 627 | pci_disable_msi(pdev); |
599 | pci_release_regions(pdev); | 628 | pci_release_regions(pdev); |
600 | pci_disable_device(pdev); | 629 | pci_disable_device(pdev); |