brcm2708: update against latest rpi-3.10.y branch
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.10 / 0108-vchiq-create_pagelist-copes-with-vmalloc-memory.patch
1 From 974102eef65cd2576157b089db47386c5b29dee6 Mon Sep 17 00:00:00 2001
2 From: Vincent Sanders <vincent.sanders@collabora.co.uk>
3 Date: Mon, 2 Sep 2013 16:44:57 +0100
4 Subject: [PATCH 108/174] vchiq: create_pagelist copes with vmalloc memory
5
6 Signed-off-by: Daniel Stone <daniels@collabora.com>
7 ---
8 .../interface/vchiq_arm/vchiq_2835_arm.c | 83 ++++++++++++++--------
9 1 file changed, 53 insertions(+), 30 deletions(-)
10
11 --- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
12 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
13 @@ -374,6 +374,7 @@ create_pagelist(char __user *buf, size_t
14 unsigned int num_pages, offset, i;
15 char *addr, *base_addr, *next_addr;
16 int run, addridx, actual_pages;
17 + unsigned long *need_release;
18
19 offset = (unsigned int)buf & (PAGE_SIZE - 1);
20 num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE;
21 @@ -384,9 +385,10 @@ create_pagelist(char __user *buf, size_t
22 ** list
23 */
24 pagelist = kmalloc(sizeof(PAGELIST_T) +
25 - (num_pages * sizeof(unsigned long)) +
26 - (num_pages * sizeof(pages[0])),
27 - GFP_KERNEL);
28 + (num_pages * sizeof(unsigned long)) +
29 + sizeof(unsigned long) +
30 + (num_pages * sizeof(pages[0])),
31 + GFP_KERNEL);
32
33 vchiq_log_trace(vchiq_arm_log_level,
34 "create_pagelist - %x", (unsigned int)pagelist);
35 @@ -394,28 +396,44 @@ create_pagelist(char __user *buf, size_t
36 return -ENOMEM;
37
38 addrs = pagelist->addrs;
39 - pages = (struct page **)(addrs + num_pages);
40 + need_release = (unsigned long *)(addrs + num_pages);
41 + pages = (struct page **)(addrs + num_pages + 1);
42
43 - down_read(&task->mm->mmap_sem);
44 - actual_pages = get_user_pages(task, task->mm,
45 - (unsigned long)buf & ~(PAGE_SIZE - 1), num_pages,
46 - (type == PAGELIST_READ) /*Write */ , 0 /*Force */ ,
47 - pages, NULL /*vmas */);
48 - up_read(&task->mm->mmap_sem);
49 -
50 - if (actual_pages != num_pages)
51 - {
52 - /* This is probably due to the process being killed */
53 - while (actual_pages > 0)
54 - {
55 - actual_pages--;
56 - page_cache_release(pages[actual_pages]);
57 - }
58 - kfree(pagelist);
59 - if (actual_pages == 0)
60 - actual_pages = -ENOMEM;
61 - return actual_pages;
62 - }
63 + if (is_vmalloc_addr(buf)) {
64 + for (actual_pages = 0; actual_pages < num_pages; actual_pages++) {
65 + pages[actual_pages] = vmalloc_to_page(buf + (actual_pages * PAGE_SIZE));
66 + }
67 + *need_release = 0; /* do not try and release vmalloc pages */
68 + } else {
69 + down_read(&task->mm->mmap_sem);
70 + actual_pages = get_user_pages(task, task->mm,
71 + (unsigned long)buf & ~(PAGE_SIZE - 1),
72 + num_pages,
73 + (type == PAGELIST_READ) /*Write */ ,
74 + 0 /*Force */ ,
75 + pages,
76 + NULL /*vmas */);
77 + up_read(&task->mm->mmap_sem);
78 +
79 + if (actual_pages != num_pages) {
80 + vchiq_log_info(vchiq_arm_log_level,
81 + "create_pagelist - only %d/%d pages locked",
82 + actual_pages,
83 + num_pages);
84 +
85 + /* This is probably due to the process being killed */
86 + while (actual_pages > 0)
87 + {
88 + actual_pages--;
89 + page_cache_release(pages[actual_pages]);
90 + }
91 + kfree(pagelist);
92 + if (actual_pages == 0)
93 + actual_pages = -ENOMEM;
94 + return actual_pages;
95 + }
96 + *need_release = 1; /* release user pages */
97 + }
98
99 pagelist->length = count;
100 pagelist->type = type;
101 @@ -482,6 +500,7 @@ create_pagelist(char __user *buf, size_t
102 static void
103 free_pagelist(PAGELIST_T *pagelist, int actual)
104 {
105 + unsigned long *need_release;
106 struct page **pages;
107 unsigned int num_pages, i;
108
109 @@ -492,7 +511,8 @@ free_pagelist(PAGELIST_T *pagelist, int
110 (pagelist->length + pagelist->offset + PAGE_SIZE - 1) /
111 PAGE_SIZE;
112
113 - pages = (struct page **)(pagelist->addrs + num_pages);
114 + need_release = (unsigned long *)(pagelist->addrs + num_pages);
115 + pages = (struct page **)(pagelist->addrs + num_pages + 1);
116
117 /* Deal with any partial cache lines (fragments) */
118 if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
119 @@ -528,11 +548,14 @@ free_pagelist(PAGELIST_T *pagelist, int
120 up(&g_free_fragments_sema);
121 }
122
123 - for (i = 0; i < num_pages; i++) {
124 - if (pagelist->type != PAGELIST_WRITE)
125 - set_page_dirty(pages[i]);
126 - page_cache_release(pages[i]);
127 - }
128 + if (*need_release) {
129 + for (i = 0; i < num_pages; i++) {
130 + if (pagelist->type != PAGELIST_WRITE)
131 + set_page_dirty(pages[i]);
132 +
133 + page_cache_release(pages[i]);
134 + }
135 + }
136
137 kfree(pagelist);
138 }