scsi: qedi: Fix bad pte call trace when iscsiuio is stopped.
munmap done by iscsiuio during a stop of the service triggers a "bad
pte" warning sometimes. munmap kernel path goes through the mmapped
pages and has a validation check for mapcount (in struct page) to be
zero or above. kzalloc, which we had used to allocate udev->ctrl, uses
slab allocations, which re-uses mapcount (union) for other purposes that
can make the mapcount look negative. Avoid all these trouble by invoking
one of the __get_free_pages wrappers to be used instead of kzalloc for
udev->ctrl.
BUG: Bad page map in process iscsiuio pte:80000000aa624067 pmd:3e6777067
page:ffffea0002a98900 count:2 mapcount:-2143289280
mapping: (null) index:0xffff8800aa624e00
page flags: 0x10075d00000090(dirty|slab)
page dumped because: bad pte
addr:00007fcba70a3000 vm_flags:0c0400fb anon_vma: (null)
mapping:ffff8803edf66e90 index:0
Call Trace:
dump_stack+0x19/0x1b
print_bad_pte+0x1af/0x250
unmap_page_range+0x7a7/0x8a0
unmap_single_vma+0x81/0xf0
unmap_vmas+0x49/0x90
unmap_region+0xbe/0x140
? vma_rb_erase+0x121/0x220
do_munmap+0x245/0x420
vm_munmap+0x41/0x60
SyS_munmap+0x22/0x30
tracesys+0xdd/0xe2
Signed-off-by: Arun Easi <arun.easi@cavium.com>
Signed-off-by: Manish Rangankar <manish.rangankar@cavium.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
committed by
Martin K. Petersen
parent
0648a07c9b
commit
5e901d0b15
@@ -151,6 +151,11 @@ static int qedi_uio_close(struct uio_info *uinfo, struct inode *inode)
|
|||||||
|
|
||||||
static void __qedi_free_uio_rings(struct qedi_uio_dev *udev)
|
static void __qedi_free_uio_rings(struct qedi_uio_dev *udev)
|
||||||
{
|
{
|
||||||
|
if (udev->uctrl) {
|
||||||
|
free_page((unsigned long)udev->uctrl);
|
||||||
|
udev->uctrl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (udev->ll2_ring) {
|
if (udev->ll2_ring) {
|
||||||
free_page((unsigned long)udev->ll2_ring);
|
free_page((unsigned long)udev->ll2_ring);
|
||||||
udev->ll2_ring = NULL;
|
udev->ll2_ring = NULL;
|
||||||
@@ -169,7 +174,6 @@ static void __qedi_free_uio(struct qedi_uio_dev *udev)
|
|||||||
__qedi_free_uio_rings(udev);
|
__qedi_free_uio_rings(udev);
|
||||||
|
|
||||||
pci_dev_put(udev->pdev);
|
pci_dev_put(udev->pdev);
|
||||||
kfree(udev->uctrl);
|
|
||||||
kfree(udev);
|
kfree(udev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +212,11 @@ static int __qedi_alloc_uio_rings(struct qedi_uio_dev *udev)
|
|||||||
if (udev->ll2_ring || udev->ll2_buf)
|
if (udev->ll2_ring || udev->ll2_buf)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
/* Memory for control area. */
|
||||||
|
udev->uctrl = (void *)get_zeroed_page(GFP_KERNEL);
|
||||||
|
if (!udev->uctrl)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Allocating memory for LL2 ring */
|
/* Allocating memory for LL2 ring */
|
||||||
udev->ll2_ring_size = QEDI_PAGE_SIZE;
|
udev->ll2_ring_size = QEDI_PAGE_SIZE;
|
||||||
udev->ll2_ring = (void *)get_zeroed_page(GFP_KERNEL | __GFP_COMP);
|
udev->ll2_ring = (void *)get_zeroed_page(GFP_KERNEL | __GFP_COMP);
|
||||||
@@ -237,7 +246,6 @@ exit_alloc_ring:
|
|||||||
static int qedi_alloc_uio_rings(struct qedi_ctx *qedi)
|
static int qedi_alloc_uio_rings(struct qedi_ctx *qedi)
|
||||||
{
|
{
|
||||||
struct qedi_uio_dev *udev = NULL;
|
struct qedi_uio_dev *udev = NULL;
|
||||||
struct qedi_uio_ctrl *uctrl = NULL;
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
list_for_each_entry(udev, &qedi_udev_list, list) {
|
list_for_each_entry(udev, &qedi_udev_list, list) {
|
||||||
@@ -258,21 +266,14 @@ static int qedi_alloc_uio_rings(struct qedi_ctx *qedi)
|
|||||||
goto err_udev;
|
goto err_udev;
|
||||||
}
|
}
|
||||||
|
|
||||||
uctrl = kzalloc(sizeof(*uctrl), GFP_KERNEL);
|
|
||||||
if (!uctrl) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_uctrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
udev->uio_dev = -1;
|
udev->uio_dev = -1;
|
||||||
|
|
||||||
udev->qedi = qedi;
|
udev->qedi = qedi;
|
||||||
udev->pdev = qedi->pdev;
|
udev->pdev = qedi->pdev;
|
||||||
udev->uctrl = uctrl;
|
|
||||||
|
|
||||||
rc = __qedi_alloc_uio_rings(udev);
|
rc = __qedi_alloc_uio_rings(udev);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_uio_rings;
|
goto err_uctrl;
|
||||||
|
|
||||||
list_add(&udev->list, &qedi_udev_list);
|
list_add(&udev->list, &qedi_udev_list);
|
||||||
|
|
||||||
@@ -283,8 +284,6 @@ static int qedi_alloc_uio_rings(struct qedi_ctx *qedi)
|
|||||||
udev->rx_pkt = udev->ll2_buf + LL2_SINGLE_BUF_SIZE;
|
udev->rx_pkt = udev->ll2_buf + LL2_SINGLE_BUF_SIZE;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_uio_rings:
|
|
||||||
kfree(uctrl);
|
|
||||||
err_uctrl:
|
err_uctrl:
|
||||||
kfree(udev);
|
kfree(udev);
|
||||||
err_udev:
|
err_udev:
|
||||||
|
|||||||
Reference in New Issue
Block a user