aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-15 11:18:44 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-15 11:18:44 -0400
commit3d06f7a5f74a813cee817c4b30b5e6f0398da0be (patch)
tree2bba8ab48e9a3d70ee3161306ea47962543df855
parent13626cb91f41df803c54047172bfc7a716e36c2b (diff)
parentbdc3e603cda3433c2ccc2069d28f7f3cd319cfc6 (diff)
Merge branch 'agp-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/agp-2.6
* 'agp-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/agp-2.6: fix use after free in amd create gatt pages AGP fix race condition between unmapping and freeing pages
-rw-r--r--drivers/char/agp/agp.h7
-rw-r--r--drivers/char/agp/ali-agp.c27
-rw-r--r--drivers/char/agp/amd-k7-agp.c9
-rw-r--r--drivers/char/agp/backend.c12
-rw-r--r--drivers/char/agp/generic.c19
-rw-r--r--drivers/char/agp/i460-agp.c4
-rw-r--r--drivers/char/agp/intel-agp.c6
7 files changed, 50 insertions, 34 deletions
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 8955e7ff759a..b83824c41329 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -58,6 +58,9 @@ struct gatt_mask {
58 * devices this will probably be ignored */ 58 * devices this will probably be ignored */
59}; 59};
60 60
61#define AGP_PAGE_DESTROY_UNMAP 1
62#define AGP_PAGE_DESTROY_FREE 2
63
61struct aper_size_info_8 { 64struct aper_size_info_8 {
62 int size; 65 int size;
63 int num_entries; 66 int num_entries;
@@ -113,7 +116,7 @@ struct agp_bridge_driver {
113 struct agp_memory *(*alloc_by_type) (size_t, int); 116 struct agp_memory *(*alloc_by_type) (size_t, int);
114 void (*free_by_type)(struct agp_memory *); 117 void (*free_by_type)(struct agp_memory *);
115 void *(*agp_alloc_page)(struct agp_bridge_data *); 118 void *(*agp_alloc_page)(struct agp_bridge_data *);
116 void (*agp_destroy_page)(void *); 119 void (*agp_destroy_page)(void *, int flags);
117 int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); 120 int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
118}; 121};
119 122
@@ -267,7 +270,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type);
267struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type); 270struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type);
268void agp_generic_free_by_type(struct agp_memory *curr); 271void agp_generic_free_by_type(struct agp_memory *curr);
269void *agp_generic_alloc_page(struct agp_bridge_data *bridge); 272void *agp_generic_alloc_page(struct agp_bridge_data *bridge);
270void agp_generic_destroy_page(void *addr); 273void agp_generic_destroy_page(void *addr, int flags);
271void agp_free_key(int key); 274void agp_free_key(int key);
272int agp_num_entries(void); 275int agp_num_entries(void);
273u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command); 276u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command);
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 4941ddb78939..aa5ddb716ffb 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -156,29 +156,34 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge)
156 return addr; 156 return addr;
157} 157}
158 158
159static void ali_destroy_page(void * addr) 159static void ali_destroy_page(void * addr, int flags)
160{ 160{
161 if (addr) { 161 if (addr) {
162 global_cache_flush(); /* is this really needed? --hch */ 162 if (flags & AGP_PAGE_DESTROY_UNMAP) {
163 agp_generic_destroy_page(addr); 163 global_cache_flush(); /* is this really needed? --hch */
164 global_flush_tlb(); 164 agp_generic_destroy_page(addr, flags);
165 global_flush_tlb();
166 } else
167 agp_generic_destroy_page(addr, flags);
165 } 168 }
166} 169}
167 170
168static void m1541_destroy_page(void * addr) 171static void m1541_destroy_page(void * addr, int flags)
169{ 172{
170 u32 temp; 173 u32 temp;
171 174
172 if (addr == NULL) 175 if (addr == NULL)
173 return; 176 return;
174 177
175 global_cache_flush(); 178 if (flags & AGP_PAGE_DESTROY_UNMAP) {
179 global_cache_flush();
176 180
177 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); 181 pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
178 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, 182 pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
179 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | 183 (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
180 virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN)); 184 virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
181 agp_generic_destroy_page(addr); 185 }
186 agp_generic_destroy_page(addr, flags);
182} 187}
183 188
184 189
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index f60bca70d1fb..1405a42585e1 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -100,21 +100,16 @@ static int amd_create_gatt_pages(int nr_tables)
100 100
101 for (i = 0; i < nr_tables; i++) { 101 for (i = 0; i < nr_tables; i++) {
102 entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL); 102 entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL);
103 tables[i] = entry;
103 if (entry == NULL) { 104 if (entry == NULL) {
104 while (i > 0) {
105 kfree(tables[i-1]);
106 i--;
107 }
108 kfree(tables);
109 retval = -ENOMEM; 105 retval = -ENOMEM;
110 break; 106 break;
111 } 107 }
112 tables[i] = entry;
113 retval = amd_create_page_map(entry); 108 retval = amd_create_page_map(entry);
114 if (retval != 0) 109 if (retval != 0)
115 break; 110 break;
116 } 111 }
117 amd_irongate_private.num_tables = nr_tables; 112 amd_irongate_private.num_tables = i;
118 amd_irongate_private.gatt_pages = tables; 113 amd_irongate_private.gatt_pages = tables;
119 114
120 if (retval != 0) 115 if (retval != 0)
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 1b47c89a1b99..832ded20fe70 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -189,9 +189,11 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
189 189
190err_out: 190err_out:
191 if (bridge->driver->needs_scratch_page) { 191 if (bridge->driver->needs_scratch_page) {
192 bridge->driver->agp_destroy_page( 192 bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
193 gart_to_virt(bridge->scratch_page_real)); 193 AGP_PAGE_DESTROY_UNMAP);
194 flush_agp_mappings(); 194 flush_agp_mappings();
195 bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
196 AGP_PAGE_DESTROY_FREE);
195 } 197 }
196 if (got_gatt) 198 if (got_gatt)
197 bridge->driver->free_gatt_table(bridge); 199 bridge->driver->free_gatt_table(bridge);
@@ -215,9 +217,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
215 217
216 if (bridge->driver->agp_destroy_page && 218 if (bridge->driver->agp_destroy_page &&
217 bridge->driver->needs_scratch_page) { 219 bridge->driver->needs_scratch_page) {
218 bridge->driver->agp_destroy_page( 220 bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
219 gart_to_virt(bridge->scratch_page_real)); 221 AGP_PAGE_DESTROY_UNMAP);
220 flush_agp_mappings(); 222 flush_agp_mappings();
223 bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
224 AGP_PAGE_DESTROY_FREE);
221 } 225 }
222} 226}
223 227
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 3db4f4076ed4..64b2f6d7059d 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -195,9 +195,12 @@ void agp_free_memory(struct agp_memory *curr)
195 } 195 }
196 if (curr->page_count != 0) { 196 if (curr->page_count != 0) {
197 for (i = 0; i < curr->page_count; i++) { 197 for (i = 0; i < curr->page_count; i++) {
198 curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i])); 198 curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
199 } 199 }
200 flush_agp_mappings(); 200 flush_agp_mappings();
201 for (i = 0; i < curr->page_count; i++) {
202 curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
203 }
201 } 204 }
202 agp_free_key(curr->key); 205 agp_free_key(curr->key);
203 agp_free_page_array(curr); 206 agp_free_page_array(curr);
@@ -1176,7 +1179,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
1176EXPORT_SYMBOL(agp_generic_alloc_page); 1179EXPORT_SYMBOL(agp_generic_alloc_page);
1177 1180
1178 1181
1179void agp_generic_destroy_page(void *addr) 1182void agp_generic_destroy_page(void *addr, int flags)
1180{ 1183{
1181 struct page *page; 1184 struct page *page;
1182 1185
@@ -1184,10 +1187,14 @@ void agp_generic_destroy_page(void *addr)
1184 return; 1187 return;
1185 1188
1186 page = virt_to_page(addr); 1189 page = virt_to_page(addr);
1187 unmap_page_from_agp(page); 1190 if (flags & AGP_PAGE_DESTROY_UNMAP)
1188 put_page(page); 1191 unmap_page_from_agp(page);
1189 free_page((unsigned long)addr); 1192
1190 atomic_dec(&agp_bridge->current_memory_agp); 1193 if (flags & AGP_PAGE_DESTROY_FREE) {
1194 put_page(page);
1195 free_page((unsigned long)addr);
1196 atomic_dec(&agp_bridge->current_memory_agp);
1197 }
1191} 1198}
1192EXPORT_SYMBOL(agp_generic_destroy_page); 1199EXPORT_SYMBOL(agp_generic_destroy_page);
1193 1200
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 75d2aca6353d..70117df4d067 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -536,10 +536,10 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
536 return page; 536 return page;
537} 537}
538 538
539static void i460_destroy_page (void *page) 539static void i460_destroy_page (void *page, int flags)
540{ 540{
541 if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { 541 if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
542 agp_generic_destroy_page(page); 542 agp_generic_destroy_page(page, flags);
543 global_flush_tlb(); 543 global_flush_tlb();
544 } 544 }
545} 545}
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 141ca176c397..d87961993ccf 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -400,9 +400,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
400 if (curr->page_count == 4) 400 if (curr->page_count == 4)
401 i8xx_destroy_pages(gart_to_virt(curr->memory[0])); 401 i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
402 else { 402 else {
403 agp_bridge->driver->agp_destroy_page( 403 agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
404 gart_to_virt(curr->memory[0])); 404 AGP_PAGE_DESTROY_UNMAP);
405 global_flush_tlb(); 405 global_flush_tlb();
406 agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
407 AGP_PAGE_DESTROY_FREE);
406 } 408 }
407 agp_free_page_array(curr); 409 agp_free_page_array(curr);
408 } 410 }