Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/nouveau: fix command submission to use vmalloc for big allocations

I was getting a order 4 allocation failure from kmalloc when testing some
game after a few days uptime with some suspend/resumes.

For big allocations vmalloc should be used instead.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

authored by

Maarten Lankhorst and committed by
Ben Skeggs
c859074e c072470f

+20 -7
+20 -7
drivers/gpu/drm/nouveau/nouveau_gem.c
··· 579 579 return 0; 580 580 } 581 581 582 + static inline void 583 + u_free(void *addr) 584 + { 585 + if (!is_vmalloc_addr(addr)) 586 + kfree(addr); 587 + else 588 + vfree(addr); 589 + } 590 + 582 591 static inline void * 583 592 u_memcpya(uint64_t user, unsigned nmemb, unsigned size) 584 593 { 585 594 void *mem; 586 595 void __user *userptr = (void __force __user *)(uintptr_t)user; 587 596 588 - mem = kmalloc(nmemb * size, GFP_KERNEL); 597 + size *= nmemb; 598 + 599 + mem = kmalloc(size, GFP_KERNEL | __GFP_NOWARN); 600 + if (!mem) 601 + mem = vmalloc(size); 589 602 if (!mem) 590 603 return ERR_PTR(-ENOMEM); 591 604 592 - if (DRM_COPY_FROM_USER(mem, userptr, nmemb * size)) { 593 - kfree(mem); 605 + if (DRM_COPY_FROM_USER(mem, userptr, size)) { 606 + u_free(mem); 594 607 return ERR_PTR(-EFAULT); 595 608 } 596 609 ··· 689 676 nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data); 690 677 } 691 678 692 - kfree(reloc); 679 + u_free(reloc); 693 680 return ret; 694 681 } 695 682 ··· 751 738 752 739 bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); 753 740 if (IS_ERR(bo)) { 754 - kfree(push); 741 + u_free(push); 755 742 return nouveau_abi16_put(abi16, PTR_ERR(bo)); 756 743 } 757 744 ··· 862 849 nouveau_fence_unref(&fence); 863 850 864 851 out_prevalid: 865 - kfree(bo); 866 - kfree(push); 852 + u_free(bo); 853 + u_free(push); 867 854 868 855 out_next: 869 856 if (chan->dma.ib_max) {