aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaya Kumar <jayakumar.lkml@gmail.com>2008-07-12 16:47:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-12 17:33:41 -0400
commitf31ad92f34913043cf008d6e479e92dfbaf02df1 (patch)
tree5f57faa359a060c56bddac6f22c2993e2309d911
parent4fc89e3911aa5357b55b85b60c4beaeb8a48a290 (diff)
fbdev: bugfix for multiprocess defio
This patch is a bugfix for how defio handles multiple processes manipulating the same framebuffer. Thanks to Bernard Blackham for identifying this bug. It occurs when two applications mmap the same framebuffer and concurrently write to the same page. Normally, this doesn't occur since only a single process mmaps the framebuffer. The symptom of the bug is that the mapping applications will hang. The cause is that defio incorrectly tries to add the same page twice to the pagelist. The solution I have is to walk the pagelist and check for a duplicate before adding. Since I needed to walk the pagelist, I now also keep the pagelist in sorted order. Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com> Cc: Bernard Blackham <bernard@largestprime.net> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/video/fb_defio.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 24843fdd5395..59df132cc375 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -74,6 +74,7 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
74{ 74{
75 struct fb_info *info = vma->vm_private_data; 75 struct fb_info *info = vma->vm_private_data;
76 struct fb_deferred_io *fbdefio = info->fbdefio; 76 struct fb_deferred_io *fbdefio = info->fbdefio;
77 struct page *cur;
77 78
78 /* this is a callback we get when userspace first tries to 79 /* this is a callback we get when userspace first tries to
79 write to the page. we schedule a workqueue. that workqueue 80 write to the page. we schedule a workqueue. that workqueue
@@ -83,7 +84,24 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
83 84
84 /* protect against the workqueue changing the page list */ 85 /* protect against the workqueue changing the page list */
85 mutex_lock(&fbdefio->lock); 86 mutex_lock(&fbdefio->lock);
86 list_add(&page->lru, &fbdefio->pagelist); 87
88 /* we loop through the pagelist before adding in order
89 to keep the pagelist sorted */
90 list_for_each_entry(cur, &fbdefio->pagelist, lru) {
91 /* this check is to catch the case where a new
92 process could start writing to the same page
93 through a new pte. this new access can cause the
94 mkwrite even when the original ps's pte is marked
95 writable */
96 if (unlikely(cur == page))
97 goto page_already_added;
98 else if (cur->index > page->index)
99 break;
100 }
101
102 list_add_tail(&page->lru, &cur->lru);
103
104page_already_added:
87 mutex_unlock(&fbdefio->lock); 105 mutex_unlock(&fbdefio->lock);
88 106
89 /* come back after delay to process the deferred IO */ 107 /* come back after delay to process the deferred IO */