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

Configure Feed

Select the types of activity you want to include in your feed.

fbdev: defio: Disconnect deferred I/O from the lifetime of struct fb_info

Hold state of deferred I/O in struct fb_deferred_io_state. Allocate an
instance as part of initializing deferred I/O and remove it only after
the final mapping has been closed. If the fb_info and the contained
deferred I/O meanwhile goes away, clear struct fb_deferred_io_state.info
to invalidate the mapping. Any access will then result in a SIGBUS
signal.

Fixes a long-standing problem, where a device hot-unplug happens while
user space still has an active mapping of the graphics memory. The hot-
unplug frees the instance of struct fb_info. Accessing the memory will
operate on undefined state.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Fixes: 60b59beafba8 ("fbdev: mm: Deferred IO support")
Cc: Helge Deller <deller@gmx.de>
Cc: linux-fbdev@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: stable@vger.kernel.org # v2.6.22+
Signed-off-by: Helge Deller <deller@gmx.de>

authored by

Thomas Zimmermann and committed by
Helge Deller
9ded47ad 24d11b25

+145 -37
+142 -36
drivers/video/fbdev/core/fb_defio.c
··· 24 24 #include <linux/rmap.h> 25 25 #include <linux/pagemap.h> 26 26 27 + /* 28 + * struct fb_deferred_io_state 29 + */ 30 + 31 + struct fb_deferred_io_state { 32 + struct kref ref; 33 + 34 + struct mutex lock; /* mutex that protects the pageref list */ 35 + /* fields protected by lock */ 36 + struct fb_info *info; 37 + }; 38 + 39 + static struct fb_deferred_io_state *fb_deferred_io_state_alloc(void) 40 + { 41 + struct fb_deferred_io_state *fbdefio_state; 42 + 43 + fbdefio_state = kzalloc_obj(*fbdefio_state); 44 + if (!fbdefio_state) 45 + return NULL; 46 + 47 + kref_init(&fbdefio_state->ref); 48 + mutex_init(&fbdefio_state->lock); 49 + 50 + return fbdefio_state; 51 + } 52 + 53 + static void fb_deferred_io_state_release(struct fb_deferred_io_state *fbdefio_state) 54 + { 55 + mutex_destroy(&fbdefio_state->lock); 56 + 57 + kfree(fbdefio_state); 58 + } 59 + 60 + static void fb_deferred_io_state_get(struct fb_deferred_io_state *fbdefio_state) 61 + { 62 + kref_get(&fbdefio_state->ref); 63 + } 64 + 65 + static void __fb_deferred_io_state_release(struct kref *ref) 66 + { 67 + struct fb_deferred_io_state *fbdefio_state = 68 + container_of(ref, struct fb_deferred_io_state, ref); 69 + 70 + fb_deferred_io_state_release(fbdefio_state); 71 + } 72 + 73 + static void fb_deferred_io_state_put(struct fb_deferred_io_state *fbdefio_state) 74 + { 75 + kref_put(&fbdefio_state->ref, __fb_deferred_io_state_release); 76 + } 77 + 78 + /* 79 + * struct vm_operations_struct 80 + */ 81 + 82 + static void fb_deferred_io_vm_open(struct vm_area_struct *vma) 83 + { 84 + struct fb_deferred_io_state *fbdefio_state = vma->vm_private_data; 85 + 86 + fb_deferred_io_state_get(fbdefio_state); 87 + } 88 + 89 + static void fb_deferred_io_vm_close(struct vm_area_struct *vma) 90 + { 91 + struct fb_deferred_io_state *fbdefio_state = vma->vm_private_data; 92 + 93 + fb_deferred_io_state_put(fbdefio_state); 94 + } 95 + 27 96 static struct page *fb_deferred_io_get_page(struct fb_info *info, unsigned long offs) 28 97 { 29 98 struct fb_deferred_io *fbdefio = info->fbdefio; ··· 190 121 /* this is to find and return the vmalloc-ed fb pages */ 191 122 static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf) 192 123 { 124 + struct fb_info *info; 193 125 unsigned long offset; 194 126 struct page *page; 195 - struct fb_info *info = vmf->vma->vm_private_data; 127 + vm_fault_t ret; 128 + struct fb_deferred_io_state *fbdefio_state = vmf->vma->vm_private_data; 129 + 130 + mutex_lock(&fbdefio_state->lock); 131 + 132 + info = fbdefio_state->info; 133 + if (!info) { 134 + ret = VM_FAULT_SIGBUS; /* our device is gone */ 135 + goto err_mutex_unlock; 136 + } 196 137 197 138 offset = vmf->pgoff << PAGE_SHIFT; 198 - if (offset >= info->fix.smem_len) 199 - return VM_FAULT_SIGBUS; 139 + if (offset >= info->fix.smem_len) { 140 + ret = VM_FAULT_SIGBUS; 141 + goto err_mutex_unlock; 142 + } 200 143 201 144 page = fb_deferred_io_get_page(info, offset); 202 - if (!page) 203 - return VM_FAULT_SIGBUS; 145 + if (!page) { 146 + ret = VM_FAULT_SIGBUS; 147 + goto err_mutex_unlock; 148 + } 204 149 205 150 if (!vmf->vma->vm_file) 206 151 fb_err(info, "no mapping available\n"); 207 152 208 153 BUG_ON(!info->fbdefio->mapping); 209 154 155 + mutex_unlock(&fbdefio_state->lock); 156 + 210 157 vmf->page = page; 158 + 211 159 return 0; 160 + 161 + err_mutex_unlock: 162 + mutex_unlock(&fbdefio_state->lock); 163 + return ret; 212 164 } 213 165 214 166 int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync) ··· 256 166 * Adds a page to the dirty list. Call this from struct 257 167 * vm_operations_struct.page_mkwrite. 258 168 */ 259 - static vm_fault_t fb_deferred_io_track_page(struct fb_info *info, unsigned long offset, 260 - struct page *page) 169 + static vm_fault_t fb_deferred_io_track_page(struct fb_deferred_io_state *fbdefio_state, 170 + unsigned long offset, struct page *page) 261 171 { 262 - struct fb_deferred_io *fbdefio = info->fbdefio; 172 + struct fb_info *info; 173 + struct fb_deferred_io *fbdefio; 263 174 struct fb_deferred_io_pageref *pageref; 264 175 vm_fault_t ret; 265 176 266 177 /* protect against the workqueue changing the page list */ 267 - mutex_lock(&fbdefio->lock); 178 + mutex_lock(&fbdefio_state->lock); 179 + 180 + info = fbdefio_state->info; 181 + if (!info) { 182 + ret = VM_FAULT_SIGBUS; /* our device is gone */ 183 + goto err_mutex_unlock; 184 + } 185 + 186 + fbdefio = info->fbdefio; 268 187 269 188 pageref = fb_deferred_io_pageref_get(info, offset, page); 270 189 if (WARN_ON_ONCE(!pageref)) { ··· 291 192 */ 292 193 lock_page(pageref->page); 293 194 294 - mutex_unlock(&fbdefio->lock); 195 + mutex_unlock(&fbdefio_state->lock); 295 196 296 197 /* come back after delay to process the deferred IO */ 297 198 schedule_delayed_work(&info->deferred_work, fbdefio->delay); 298 199 return VM_FAULT_LOCKED; 299 200 300 201 err_mutex_unlock: 301 - mutex_unlock(&fbdefio->lock); 202 + mutex_unlock(&fbdefio_state->lock); 302 203 return ret; 303 204 } 304 205 305 - /* 306 - * fb_deferred_io_page_mkwrite - Mark a page as written for deferred I/O 307 - * @fb_info: The fbdev info structure 308 - * @vmf: The VM fault 309 - * 310 - * This is a callback we get when userspace first tries to 311 - * write to the page. We schedule a workqueue. That workqueue 312 - * will eventually mkclean the touched pages and execute the 313 - * deferred framebuffer IO. Then if userspace touches a page 314 - * again, we repeat the same scheme. 315 - * 316 - * Returns: 317 - * VM_FAULT_LOCKED on success, or a VM_FAULT error otherwise. 318 - */ 319 - static vm_fault_t fb_deferred_io_page_mkwrite(struct fb_info *info, struct vm_fault *vmf) 206 + static vm_fault_t fb_deferred_io_page_mkwrite(struct fb_deferred_io_state *fbdefio_state, 207 + struct vm_fault *vmf) 320 208 { 321 209 unsigned long offset = vmf->pgoff << PAGE_SHIFT; 322 210 struct page *page = vmf->page; 323 211 324 212 file_update_time(vmf->vma->vm_file); 325 213 326 - return fb_deferred_io_track_page(info, offset, page); 214 + return fb_deferred_io_track_page(fbdefio_state, offset, page); 327 215 } 328 216 329 - /* vm_ops->page_mkwrite handler */ 330 217 static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) 331 218 { 332 - struct fb_info *info = vmf->vma->vm_private_data; 219 + struct fb_deferred_io_state *fbdefio_state = vmf->vma->vm_private_data; 333 220 334 - return fb_deferred_io_page_mkwrite(info, vmf); 221 + return fb_deferred_io_page_mkwrite(fbdefio_state, vmf); 335 222 } 336 223 337 224 static const struct vm_operations_struct fb_deferred_io_vm_ops = { 225 + .open = fb_deferred_io_vm_open, 226 + .close = fb_deferred_io_vm_close, 338 227 .fault = fb_deferred_io_fault, 339 228 .page_mkwrite = fb_deferred_io_mkwrite, 340 229 }; ··· 339 252 vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); 340 253 if (!(info->flags & FBINFO_VIRTFB)) 341 254 vm_flags_set(vma, VM_IO); 342 - vma->vm_private_data = info; 255 + vma->vm_private_data = info->fbdefio_state; 256 + 257 + fb_deferred_io_state_get(info->fbdefio_state); /* released in vma->vm_ops->close() */ 258 + 343 259 return 0; 344 260 } 345 261 EXPORT_SYMBOL_GPL(fb_deferred_io_mmap); ··· 353 263 struct fb_info *info = container_of(work, struct fb_info, deferred_work.work); 354 264 struct fb_deferred_io_pageref *pageref, *next; 355 265 struct fb_deferred_io *fbdefio = info->fbdefio; 266 + struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state; 356 267 357 268 /* here we wrprotect the page's mappings, then do all deferred IO. */ 358 - mutex_lock(&fbdefio->lock); 269 + mutex_lock(&fbdefio_state->lock); 359 270 #ifdef CONFIG_MMU 360 271 list_for_each_entry(pageref, &fbdefio->pagereflist, list) { 361 272 struct page *page = pageref->page; ··· 374 283 list_for_each_entry_safe(pageref, next, &fbdefio->pagereflist, list) 375 284 fb_deferred_io_pageref_put(pageref, info); 376 285 377 - mutex_unlock(&fbdefio->lock); 286 + mutex_unlock(&fbdefio_state->lock); 378 287 } 379 288 380 289 int fb_deferred_io_init(struct fb_info *info) 381 290 { 382 291 struct fb_deferred_io *fbdefio = info->fbdefio; 292 + struct fb_deferred_io_state *fbdefio_state; 383 293 struct fb_deferred_io_pageref *pagerefs; 384 294 unsigned long npagerefs; 385 295 int ret; ··· 390 298 if (WARN_ON(!info->fix.smem_len)) 391 299 return -EINVAL; 392 300 393 - mutex_init(&fbdefio->lock); 301 + fbdefio_state = fb_deferred_io_state_alloc(); 302 + if (!fbdefio_state) 303 + return -ENOMEM; 304 + fbdefio_state->info = info; 305 + 394 306 INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work); 395 307 INIT_LIST_HEAD(&fbdefio->pagereflist); 396 308 if (fbdefio->delay == 0) /* set a default of 1 s */ ··· 411 315 info->npagerefs = npagerefs; 412 316 info->pagerefs = pagerefs; 413 317 318 + info->fbdefio_state = fbdefio_state; 319 + 414 320 return 0; 415 321 416 322 err: 417 - mutex_destroy(&fbdefio->lock); 323 + fb_deferred_io_state_release(fbdefio_state); 418 324 return ret; 419 325 } 420 326 EXPORT_SYMBOL_GPL(fb_deferred_io_init); ··· 450 352 void fb_deferred_io_cleanup(struct fb_info *info) 451 353 { 452 354 struct fb_deferred_io *fbdefio = info->fbdefio; 355 + struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state; 453 356 454 357 fb_deferred_io_lastclose(info); 455 358 359 + info->fbdefio_state = NULL; 360 + 361 + mutex_lock(&fbdefio_state->lock); 362 + fbdefio_state->info = NULL; 363 + mutex_unlock(&fbdefio_state->lock); 364 + 365 + fb_deferred_io_state_put(fbdefio_state); 366 + 456 367 kvfree(info->pagerefs); 457 - mutex_destroy(&fbdefio->lock); 458 368 fbdefio->mapping = NULL; 459 369 } 460 370 EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
+3 -1
include/linux/fb.h
··· 218 218 unsigned long delay; 219 219 bool sort_pagereflist; /* sort pagelist by offset */ 220 220 int open_count; /* number of opened files; protected by fb_info lock */ 221 - struct mutex lock; /* mutex that protects the pageref list */ 222 221 struct list_head pagereflist; /* list of pagerefs for touched pages */ 223 222 struct address_space *mapping; /* page cache object for fb device */ 224 223 /* callback */ 225 224 struct page *(*get_page)(struct fb_info *info, unsigned long offset); 226 225 void (*deferred_io)(struct fb_info *info, struct list_head *pagelist); 227 226 }; 227 + 228 + struct fb_deferred_io_state; 228 229 #endif 229 230 230 231 /* ··· 488 487 unsigned long npagerefs; 489 488 struct fb_deferred_io_pageref *pagerefs; 490 489 struct fb_deferred_io *fbdefio; 490 + struct fb_deferred_io_state *fbdefio_state; 491 491 #endif 492 492 493 493 const struct fb_ops *fbops;