aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-11 17:58:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-12 10:46:43 -0400
commitc47747fde931c02455683bd00ea43eaa62f35b0e (patch)
treea98fbf2b466cabbc71a685a24496e08e074ecfb2 /drivers
parent698b368275c3fa98261159253cfc79653f9dffc6 (diff)
fbmem: make read/write/ioctl use the frame buffer at open time
read/write/ioctl on a fbcon file descriptor has traditionally used the fbcon not when it was opened, but as it was at the time of the call. That makes no sense, but the lack of sense is much more obvious now that we properly ref-count the usage - it means that the ref-counting doesn't actually protect operations we do on the frame buffer. This changes it to look at the fb_info that we got at open time, but in order to avoid using a frame buffer long after it has been unregistered, we do verify that it is still current, and return -ENODEV if not. Acked-by: Tim Gardner <tim.gardner@canonical.com> Tested-by: Daniel J Blueman <daniel.blueman@gmail.com> Tested-by: Anca Emanuel <anca.emanuel@gmail.com> Cc: Bruno Prémont <bonbons@linux-vserver.org> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: Paul Mundt <lethal@linux-sh.org> Cc: Dave Airlie <airlied@redhat.com> Cc: Andy Whitcroft <andy.whitcroft@canonical.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/fbmem.c50
1 files changed, 34 insertions, 16 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index eec14d2ca1c7..ea16e654a9b6 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -717,13 +717,30 @@ static const struct file_operations fb_proc_fops = {
717 .release = seq_release, 717 .release = seq_release,
718}; 718};
719 719
720static ssize_t 720/*
721fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 721 * We hold a reference to the fb_info in file->private_data,
722 * but if the current registered fb has changed, we don't
723 * actually want to use it.
724 *
725 * So look up the fb_info using the inode minor number,
726 * and just verify it against the reference we have.
727 */
728static struct fb_info *file_fb_info(struct file *file)
722{ 729{
723 unsigned long p = *ppos;
724 struct inode *inode = file->f_path.dentry->d_inode; 730 struct inode *inode = file->f_path.dentry->d_inode;
725 int fbidx = iminor(inode); 731 int fbidx = iminor(inode);
726 struct fb_info *info = registered_fb[fbidx]; 732 struct fb_info *info = registered_fb[fbidx];
733
734 if (info != file->private_data)
735 info = NULL;
736 return info;
737}
738
739static ssize_t
740fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
741{
742 unsigned long p = *ppos;
743 struct fb_info *info = file_fb_info(file);
727 u8 *buffer, *dst; 744 u8 *buffer, *dst;
728 u8 __iomem *src; 745 u8 __iomem *src;
729 int c, cnt = 0, err = 0; 746 int c, cnt = 0, err = 0;
@@ -788,9 +805,7 @@ static ssize_t
788fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 805fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
789{ 806{
790 unsigned long p = *ppos; 807 unsigned long p = *ppos;
791 struct inode *inode = file->f_path.dentry->d_inode; 808 struct fb_info *info = file_fb_info(file);
792 int fbidx = iminor(inode);
793 struct fb_info *info = registered_fb[fbidx];
794 u8 *buffer, *src; 809 u8 *buffer, *src;
795 u8 __iomem *dst; 810 u8 __iomem *dst;
796 int c, cnt = 0, err = 0; 811 int c, cnt = 0, err = 0;
@@ -1168,10 +1183,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1168 1183
1169static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 1184static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1170{ 1185{
1171 struct inode *inode = file->f_path.dentry->d_inode; 1186 struct fb_info *info = file_fb_info(file);
1172 int fbidx = iminor(inode);
1173 struct fb_info *info = registered_fb[fbidx];
1174 1187
1188 if (!info)
1189 return -ENODEV;
1175 return do_fb_ioctl(info, cmd, arg); 1190 return do_fb_ioctl(info, cmd, arg);
1176} 1191}
1177 1192
@@ -1292,12 +1307,13 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
1292static long fb_compat_ioctl(struct file *file, unsigned int cmd, 1307static long fb_compat_ioctl(struct file *file, unsigned int cmd,
1293 unsigned long arg) 1308 unsigned long arg)
1294{ 1309{
1295 struct inode *inode = file->f_path.dentry->d_inode; 1310 struct fb_info *info = file_fb_info(file);
1296 int fbidx = iminor(inode); 1311 struct fb_ops *fb;
1297 struct fb_info *info = registered_fb[fbidx];
1298 struct fb_ops *fb = info->fbops;
1299 long ret = -ENOIOCTLCMD; 1312 long ret = -ENOIOCTLCMD;
1300 1313
1314 if (!info)
1315 return -ENODEV;
1316 fb = info->fbops;
1301 switch(cmd) { 1317 switch(cmd) {
1302 case FBIOGET_VSCREENINFO: 1318 case FBIOGET_VSCREENINFO:
1303 case FBIOPUT_VSCREENINFO: 1319 case FBIOPUT_VSCREENINFO:
@@ -1330,16 +1346,18 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
1330static int 1346static int
1331fb_mmap(struct file *file, struct vm_area_struct * vma) 1347fb_mmap(struct file *file, struct vm_area_struct * vma)
1332{ 1348{
1333 int fbidx = iminor(file->f_path.dentry->d_inode); 1349 struct fb_info *info = file_fb_info(file);
1334 struct fb_info *info = registered_fb[fbidx]; 1350 struct fb_ops *fb;
1335 struct fb_ops *fb = info->fbops;
1336 unsigned long off; 1351 unsigned long off;
1337 unsigned long start; 1352 unsigned long start;
1338 u32 len; 1353 u32 len;
1339 1354
1355 if (!info)
1356 return -ENODEV;
1340 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 1357 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1341 return -EINVAL; 1358 return -EINVAL;
1342 off = vma->vm_pgoff << PAGE_SHIFT; 1359 off = vma->vm_pgoff << PAGE_SHIFT;
1360 fb = info->fbops;
1343 if (!fb) 1361 if (!fb)
1344 return -ENODEV; 1362 return -ENODEV;
1345 mutex_lock(&info->mm_lock); 1363 mutex_lock(&info->mm_lock);