diff options
-rw-r--r-- | drivers/video/fbmem.c | 50 |
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 | ||
720 | static ssize_t | 720 | /* |
721 | fb_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 | */ | ||
728 | static 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 | |||
739 | static ssize_t | ||
740 | fb_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 | |||
788 | fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 805 | fb_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 | ||
1169 | static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1184 | static 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, | |||
1292 | static long fb_compat_ioctl(struct file *file, unsigned int cmd, | 1307 | static 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, | |||
1330 | static int | 1346 | static int |
1331 | fb_mmap(struct file *file, struct vm_area_struct * vma) | 1347 | fb_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); |