From: Thomas Hellstrom <thellstrom@vmware.com>
To: j.glisse@gmail.com
Cc: Jerome Glisse <jglisse@redhat.com>, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH 05/12] drm/ttm: convert page allocation to use page ptr array instead of list V3
Date: Tue, 08 Nov 2011 09:11:20 +0100 [thread overview]
Message-ID: <4EB8E428.7080500@vmware.com> (raw)
In-Reply-To: <1320709232-29477-6-git-send-email-j.glisse@gmail.com>
On 11/08/2011 12:40 AM, j.glisse@gmail.com wrote:
> From: Jerome Glisse<jglisse@redhat.com>
>
> Use the ttm_tt page ptr array for page allocation, move the list to
> array unwinding into the page allocation functions.
>
> V2 split the fix to use ttm put page as a separate fix
> properly fill pages array when TTM_PAGE_FLAG_ZERO_ALLOC is not
> set
> V3 Added back page_count()==1 check when freeing page
>
NAK, this patch introduces a DOS vulnerability. It's allowing an
arbitrary number of pages to be
allocated *before* accounting them. Currently TTM is allowing a "small"
(page size) memory size to be allocated before accounting. So page
allocation must be interleaved with accounting on a per-page basis
unless we can figure out a way to do the accounting *before* allocating
the pages.
/Thomas
> Signed-off-by: Jerome Glisse<jglisse@redhat.com>
> Reviewed-by: Konrad Rzeszutek Wilk<konrad.wilk@oracle.com>
> ---
> drivers/gpu/drm/ttm/ttm_memory.c | 44 +++++++++++------
> drivers/gpu/drm/ttm/ttm_page_alloc.c | 90 ++++++++++++++++++++--------------
> drivers/gpu/drm/ttm/ttm_tt.c | 61 ++++++++---------------
> include/drm/ttm/ttm_memory.h | 11 ++--
> include/drm/ttm/ttm_page_alloc.h | 17 +++---
> 5 files changed, 115 insertions(+), 108 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c
> index e70ddd8..3a3a58b 100644
> --- a/drivers/gpu/drm/ttm/ttm_memory.c
> +++ b/drivers/gpu/drm/ttm/ttm_memory.c
> @@ -543,41 +543,53 @@ int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory,
> }
> EXPORT_SYMBOL(ttm_mem_global_alloc);
>
> -int ttm_mem_global_alloc_page(struct ttm_mem_global *glob,
> - struct page *page,
> - bool no_wait, bool interruptible)
> +int ttm_mem_global_alloc_pages(struct ttm_mem_global *glob,
> + struct page **pages,
> + unsigned npages,
> + bool no_wait, bool interruptible)
> {
>
> struct ttm_mem_zone *zone = NULL;
> + unsigned i;
> + int r;
>
> /**
> * Page allocations may be registed in a single zone
> * only if highmem or !dma32.
> */
> -
> + for (i = 0; i< npages; i++) {
> #ifdef CONFIG_HIGHMEM
> - if (PageHighMem(page)&& glob->zone_highmem != NULL)
> - zone = glob->zone_highmem;
> + if (PageHighMem(pages[i])&& glob->zone_highmem != NULL)
> + zone = glob->zone_highmem;
> #else
> - if (glob->zone_dma32&& page_to_pfn(page)> 0x00100000UL)
> - zone = glob->zone_kernel;
> + if (glob->zone_dma32&& page_to_pfn(pages[i])> 0x00100000UL)
> + zone = glob->zone_kernel;
> #endif
> - return ttm_mem_global_alloc_zone(glob, zone, PAGE_SIZE, no_wait,
> - interruptible);
> + r = ttm_mem_global_alloc_zone(glob, zone, PAGE_SIZE, no_wait,
> + interruptible);
> + if (r) {
> + return r;
> + }
> + }
> + return 0;
> }
>
> -void ttm_mem_global_free_page(struct ttm_mem_global *glob, struct page *page)
> +void ttm_mem_global_free_pages(struct ttm_mem_global *glob,
> + struct page **pages, unsigned npages)
> {
> struct ttm_mem_zone *zone = NULL;
> + unsigned i;
>
> + for (i = 0; i< npages; i++) {
> #ifdef CONFIG_HIGHMEM
> - if (PageHighMem(page)&& glob->zone_highmem != NULL)
> - zone = glob->zone_highmem;
> + if (PageHighMem(pages[i])&& glob->zone_highmem != NULL)
> + zone = glob->zone_highmem;
> #else
> - if (glob->zone_dma32&& page_to_pfn(page)> 0x00100000UL)
> - zone = glob->zone_kernel;
> + if (glob->zone_dma32&& page_to_pfn(pages[i])> 0x00100000UL)
> + zone = glob->zone_kernel;
> #endif
> - ttm_mem_global_free_zone(glob, zone, PAGE_SIZE);
> + ttm_mem_global_free_zone(glob, zone, PAGE_SIZE);
> + }
> }
>
>
> diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
> index 727e93d..c4f18b9 100644
> --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
> +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
> @@ -619,8 +619,10 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool,
> * @return count of pages still required to fulfill the request.
> */
> static unsigned ttm_page_pool_get_pages(struct ttm_page_pool *pool,
> - struct list_head *pages, int ttm_flags,
> - enum ttm_caching_state cstate, unsigned count)
> + struct list_head *pages,
> + int ttm_flags,
> + enum ttm_caching_state cstate,
> + unsigned count)
> {
> unsigned long irq_flags;
> struct list_head *p;
> @@ -664,13 +666,14 @@ out:
> * On success pages list will hold count number of correctly
> * cached pages.
> */
> -int ttm_get_pages(struct list_head *pages, int flags,
> - enum ttm_caching_state cstate, unsigned count,
> - dma_addr_t *dma_address)
> +int ttm_get_pages(struct page **pages, unsigned npages, int flags,
> + enum ttm_caching_state cstate, dma_addr_t *dma_address)
> {
> struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
> struct page *p = NULL;
> + struct list_head plist;
> gfp_t gfp_flags = GFP_USER;
> + unsigned count = 0;
> int r;
>
> /* set zero flag for page allocation if required */
> @@ -684,94 +687,107 @@ int ttm_get_pages(struct list_head *pages, int flags,
> else
> gfp_flags |= GFP_HIGHUSER;
>
> - for (r = 0; r< count; ++r) {
> - p = alloc_page(gfp_flags);
> - if (!p) {
> -
> + for (count = 0; count< npages; ++count) {
> + pages[count] = alloc_page(gfp_flags);
> + if (pages[count] == NULL) {
> printk(KERN_ERR TTM_PFX
> "Unable to allocate page.");
> return -ENOMEM;
> }
> -
> - list_add(&p->lru, pages);
> }
> return 0;
> }
>
> -
> /* combine zero flag to pool flags */
> gfp_flags |= pool->gfp_flags;
>
> /* First we take pages from the pool */
> - count = ttm_page_pool_get_pages(pool, pages, flags, cstate, count);
> + INIT_LIST_HEAD(&plist);
> + npages = ttm_page_pool_get_pages(pool,&plist, flags, cstate, npages);
>
> /* clear the pages coming from the pool if requested */
> + count = 0;
> + list_for_each_entry(p,&plist, lru) {
> + pages[count++] = p;
> + }
> if (flags& TTM_PAGE_FLAG_ZERO_ALLOC) {
> - list_for_each_entry(p, pages, lru) {
> + list_for_each_entry(p,&plist, lru) {
> clear_page(page_address(p));
> }
> }
>
> /* If pool didn't have enough pages allocate new one. */
> - if (count> 0) {
> + if (npages> 0) {
> /* ttm_alloc_new_pages doesn't reference pool so we can run
> * multiple requests in parallel.
> **/
> - r = ttm_alloc_new_pages(pages, gfp_flags, flags, cstate, count);
> + INIT_LIST_HEAD(&plist);
> + r = ttm_alloc_new_pages(&plist, gfp_flags, flags, cstate, npages);
> + list_for_each_entry(p,&plist, lru) {
> + pages[count++] = p;
> + }
> if (r) {
> /* If there is any pages in the list put them back to
> * the pool. */
> printk(KERN_ERR TTM_PFX
> "Failed to allocate extra pages "
> "for large request.");
> - ttm_put_pages(pages, 0, flags, cstate, NULL);
> + ttm_put_pages(pages, count, flags, cstate, NULL);
> return r;
> }
> }
>
> -
> return 0;
> }
>
> /* Put all pages in pages list to correct pool to wait for reuse */
> -void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags,
> +void ttm_put_pages(struct page **pages, unsigned npages, int flags,
> enum ttm_caching_state cstate, dma_addr_t *dma_address)
> {
> unsigned long irq_flags;
> struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
> - struct page *p, *tmp;
> + unsigned i;
>
> if (pool == NULL) {
> /* No pool for this memory type so free the pages */
>
> - list_for_each_entry_safe(p, tmp, pages, lru) {
> - __free_page(p);
> + for (i = 0; i< npages; i++) {
> + if (pages[i]) {
> + if (page_count(pages[i]) != 1)
> + printk(KERN_ERR TTM_PFX
> + "Erroneous page count. "
> + "Leaking pages.\n");
> + __free_page(pages[i]);
> + pages[i] = NULL;
> + }
> }
> - /* Make the pages list empty */
> - INIT_LIST_HEAD(pages);
> return;
> }
> - if (page_count == 0) {
> - list_for_each_entry_safe(p, tmp, pages, lru) {
> - ++page_count;
> - }
> - }
>
> spin_lock_irqsave(&pool->lock, irq_flags);
> - list_splice_init(pages,&pool->list);
> - pool->npages += page_count;
> + for (i = 0; i< npages; i++) {
> + if (pages[i]) {
> + if (page_count(pages[i]) != 1)
> + printk(KERN_ERR TTM_PFX
> + "Erroneous page count. "
> + "Leaking pages.\n");
> + list_add_tail(&pages[i]->lru,&pool->list);
> + pages[i] = NULL;
> + pool->npages++;
> + }
> + }
> /* Check that we don't go over the pool limit */
> - page_count = 0;
> + npages = 0;
> if (pool->npages> _manager->options.max_size) {
> - page_count = pool->npages - _manager->options.max_size;
> + npages = pool->npages - _manager->options.max_size;
> /* free at least NUM_PAGES_TO_ALLOC number of pages
> * to reduce calls to set_memory_wb */
> - if (page_count< NUM_PAGES_TO_ALLOC)
> - page_count = NUM_PAGES_TO_ALLOC;
> + if (npages< NUM_PAGES_TO_ALLOC)
> + npages = NUM_PAGES_TO_ALLOC;
> }
> spin_unlock_irqrestore(&pool->lock, irq_flags);
> - if (page_count)
> - ttm_page_pool_free(pool, page_count);
> + if (npages)
> + ttm_page_pool_free(pool, npages);
> }
>
> static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, int flags,
> diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
> index 3fb4c6d..2dd45ca 100644
> --- a/drivers/gpu/drm/ttm/ttm_tt.c
> +++ b/drivers/gpu/drm/ttm/ttm_tt.c
> @@ -65,33 +65,25 @@ static void ttm_tt_free_page_directory(struct ttm_tt *ttm)
> static struct page *__ttm_tt_get_page(struct ttm_tt *ttm, int index)
> {
> struct page *p;
> - struct list_head h;
> struct ttm_mem_global *mem_glob = ttm->glob->mem_glob;
> int ret;
>
> if (NULL == (p = ttm->pages[index])) {
>
> - INIT_LIST_HEAD(&h);
> -
> - ret = ttm_get_pages(&h, ttm->page_flags, ttm->caching_state, 1,
> + ret = ttm_get_pages(&ttm->pages[index], 1, ttm->page_flags,
> + ttm->caching_state,
> &ttm->dma_address[index]);
> -
> if (ret != 0)
> return NULL;
>
> - p = list_first_entry(&h, struct page, lru);
> -
> - ret = ttm_mem_global_alloc_page(mem_glob, p, false, false);
> + ret = ttm_mem_global_alloc_pages(mem_glob,&ttm->pages[index],
> + 1, false, false);
> if (unlikely(ret != 0))
> goto out_err;
> -
> - ttm->pages[index] = p;
> }
> return p;
> out_err:
> - INIT_LIST_HEAD(&h);
> - list_add(&p->lru,&h);
> - ttm_put_pages(&h, 1, ttm->page_flags,
> + ttm_put_pages(&ttm->pages[index], 1, ttm->page_flags,
> ttm->caching_state,&ttm->dma_address[index]);
> return NULL;
> }
> @@ -110,8 +102,7 @@ struct page *ttm_tt_get_page(struct ttm_tt *ttm, int index)
>
> int ttm_tt_populate(struct ttm_tt *ttm)
> {
> - struct page *page;
> - unsigned long i;
> + struct ttm_mem_global *mem_glob = ttm->glob->mem_glob;
> struct ttm_backend *be;
> int ret;
>
> @@ -126,10 +117,16 @@ int ttm_tt_populate(struct ttm_tt *ttm)
>
> be = ttm->be;
>
> - for (i = 0; i< ttm->num_pages; ++i) {
> - page = __ttm_tt_get_page(ttm, i);
> - if (!page)
> - return -ENOMEM;
> + ret = ttm_get_pages(ttm->pages, ttm->num_pages, ttm->page_flags,
> + ttm->caching_state, ttm->dma_address);
> + if (ret != 0)
> + return -ENOMEM;
> + ret = ttm_mem_global_alloc_pages(mem_glob, ttm->pages,
> + ttm->num_pages, false, false);
> + if (unlikely(ret != 0)) {
> + ttm_put_pages(ttm->pages, ttm->num_pages, ttm->page_flags,
> + ttm->caching_state, ttm->dma_address);
> + return -ENOMEM;
> }
>
> be->func->populate(be, ttm->num_pages, ttm->pages,
> @@ -242,33 +239,15 @@ EXPORT_SYMBOL(ttm_tt_set_placement_caching);
>
> static void ttm_tt_free_alloced_pages(struct ttm_tt *ttm)
> {
> - int i;
> - unsigned count = 0;
> - struct list_head h;
> - struct page *cur_page;
> struct ttm_backend *be = ttm->be;
> -
> - INIT_LIST_HEAD(&h);
> + struct ttm_mem_global *glob = ttm->glob->mem_glob;
>
> if (be)
> be->func->clear(be);
> - for (i = 0; i< ttm->num_pages; ++i) {
>
> - cur_page = ttm->pages[i];
> - ttm->pages[i] = NULL;
> - if (cur_page) {
> - if (page_count(cur_page) != 1)
> - printk(KERN_ERR TTM_PFX
> - "Erroneous page count. "
> - "Leaking pages.\n");
> - ttm_mem_global_free_page(ttm->glob->mem_glob,
> - cur_page);
> - list_add(&cur_page->lru,&h);
> - count++;
> - }
> - }
> - ttm_put_pages(&h, count, ttm->page_flags, ttm->caching_state,
> - ttm->dma_address);
> + ttm_mem_global_free_pages(glob, ttm->pages, ttm->num_pages);
> + ttm_put_pages(ttm->pages, ttm->num_pages, ttm->page_flags,
> + ttm->caching_state, ttm->dma_address);
> ttm->state = tt_unpopulated;
> }
>
> diff --git a/include/drm/ttm/ttm_memory.h b/include/drm/ttm/ttm_memory.h
> index 26c1f78..cee821e 100644
> --- a/include/drm/ttm/ttm_memory.h
> +++ b/include/drm/ttm/ttm_memory.h
> @@ -150,10 +150,11 @@ extern int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory,
> bool no_wait, bool interruptible);
> extern void ttm_mem_global_free(struct ttm_mem_global *glob,
> uint64_t amount);
> -extern int ttm_mem_global_alloc_page(struct ttm_mem_global *glob,
> - struct page *page,
> - bool no_wait, bool interruptible);
> -extern void ttm_mem_global_free_page(struct ttm_mem_global *glob,
> - struct page *page);
> +extern int ttm_mem_global_alloc_pages(struct ttm_mem_global *glob,
> + struct page **pages,
> + unsigned npages,
> + bool no_wait, bool interruptible);
> +extern void ttm_mem_global_free_pages(struct ttm_mem_global *glob,
> + struct page **pages, unsigned npages);
> extern size_t ttm_round_pot(size_t size);
> #endif
> diff --git a/include/drm/ttm/ttm_page_alloc.h b/include/drm/ttm/ttm_page_alloc.h
> index 129de12..fffb3bd 100644
> --- a/include/drm/ttm/ttm_page_alloc.h
> +++ b/include/drm/ttm/ttm_page_alloc.h
> @@ -32,29 +32,28 @@
> /**
> * Get count number of pages from pool to pages list.
> *
> - * @pages: head of empty linked list where pages are filled.
> + * @pages: array of pages ptr
> + * @npages: number of pages to allocate.
> * @flags: ttm flags for page allocation.
> * @cstate: ttm caching state for the page.
> - * @count: number of pages to allocate.
> * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
> */
> -int ttm_get_pages(struct list_head *pages,
> +int ttm_get_pages(struct page **pages,
> + unsigned npages,
> int flags,
> enum ttm_caching_state cstate,
> - unsigned count,
> dma_addr_t *dma_address);
> /**
> * Put linked list of pages to pool.
> *
> - * @pages: list of pages to free.
> - * @page_count: number of pages in the list. Zero can be passed for unknown
> - * count.
> + * @pages: array of pages ptr
> + * @npages: number of pages to free.
> * @flags: ttm flags for page allocation.
> * @cstate: ttm caching state.
> * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
> */
> -void ttm_put_pages(struct list_head *pages,
> - unsigned page_count,
> +void ttm_put_pages(struct page **pages,
> + unsigned npages,
> int flags,
> enum ttm_caching_state cstate,
> dma_addr_t *dma_address);
>
next prev parent reply other threads:[~2011-11-08 8:13 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-07 23:40 ttm: merge ttm_backend & ttm_tt, introduce ttm dma allocator [FULL] j.glisse
2011-11-07 23:40 ` [PATCH 01/12] drm/ttm: remove userspace backed ttm object support j.glisse
2011-11-08 7:22 ` Thomas Hellstrom
2011-11-09 20:34 ` Jerome Glisse
2011-11-08 7:44 ` Thomas Hellstrom
2011-11-07 23:40 ` [PATCH 02/12] drm/ttm: remove split btw highmen and lowmem page j.glisse
2011-11-08 7:56 ` Thomas Hellstrom
2011-11-08 15:13 ` Konrad Rzeszutek Wilk
2011-11-07 23:40 ` [PATCH 03/12] drm/ttm: remove unused backend flags field j.glisse
2011-11-08 7:56 ` Thomas Hellstrom
2011-11-07 23:40 ` [PATCH 04/12] drm/ttm: use ttm put pages function to properly restore cache attribute j.glisse
2011-11-08 7:57 ` Thomas Hellstrom
2011-11-07 23:40 ` [PATCH 05/12] drm/ttm: convert page allocation to use page ptr array instead of list V3 j.glisse
2011-11-08 8:11 ` Thomas Hellstrom [this message]
2011-11-08 16:19 ` Jerome Glisse
2011-11-07 23:40 ` [PATCH 06/12] drm/ttm: test for dma_address array allocation failure j.glisse
2011-11-08 8:12 ` Thomas Hellstrom
2011-11-07 23:40 ` [PATCH 07/12] drm/ttm: merge ttm_backend and ttm_tt j.glisse
2011-11-08 8:48 ` Thomas Hellstrom
2011-11-07 23:40 ` [PATCH 08/12] drm/ttm: introduce callback for ttm_tt populate & unpopulate j.glisse
2011-11-08 8:29 ` Thomas Hellstrom
2011-11-07 23:40 ` [PATCH 09/12] ttm: Provide DMA aware TTM page pool code j.glisse
2011-11-08 8:51 ` Thomas Hellstrom
2011-11-07 23:40 ` [PATCH 10/12] swiotlb: Expose swiotlb_nr_tlb function to modules j.glisse
2011-11-07 23:40 ` [PATCH 11/12] drm/radeon/kms: Enable the TTM DMA pool if swiotlb is on j.glisse
2011-11-07 23:40 ` [PATCH 12/12] nouveau/ttm/dma: Enable the TTM DMA pool if device can only do 32-bit DMA j.glisse
2011-11-08 15:15 ` ttm: merge ttm_backend & ttm_tt, introduce ttm dma allocator [FULL] Konrad Rzeszutek Wilk
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4EB8E428.7080500@vmware.com \
--to=thellstrom@vmware.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=j.glisse@gmail.com \
--cc=jglisse@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.