summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/core/fbmem.c
diff options
context:
space:
mode:
authorThomas Zimmermann <tzimmermann@suse.de>2023-04-28 14:24:47 +0200
committerThomas Zimmermann <tzimmermann@suse.de>2023-05-08 15:28:33 +0200
commit921b7383f34802726a7f45b6b38ef62bae0df4d6 (patch)
tree56a81c48db2873115d4fff0d118ff852cc08cf7f /drivers/video/fbdev/core/fbmem.c
parent254a4fda50590c5458f012220df3d0dc2f11fd6e (diff)
fbdev: Return number of bytes read or written
Always return the number of bytes read or written within the framebuffer. Only return an errno code if framebuffer memory was not touched. This is the semantics required by POSIX and makes fb_read() and fb_write() compatible with IGT tests. [1] This bug has been fixed for fb_write() long ago by commit 6a2a88668e90 ("[PATCH] fbdev: Fix return error of fb_write"). The code in fb_read() and the corresponding fb_sys_() helpers was forgotten. It can happen that copy_{from, to}_user() only partially copies the given buffer. Take this into account when calculating the number of bytes. v2: * consider return value from copy_{from,to}_user() (Geert) Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Tested-by: Sui Jingfeng <suijingfeng@loongson.cn> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Acked-by: Helge Deller <deller@gmx.de> Link: https://gitlab.freedesktop.org/drm/igt-gpu-tools/-/blob/master/tests/fbdev.c # 1 Link: https://patchwork.freedesktop.org/patch/msgid/20230428122452.4856-15-tzimmermann@suse.de
Diffstat (limited to 'drivers/video/fbdev/core/fbmem.c')
-rw-r--r--drivers/video/fbdev/core/fbmem.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 875541ff185b..9c79fb076c6d 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -766,7 +766,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
u8 *buffer, *dst;
u8 __iomem *src;
int c, cnt = 0, err = 0;
- unsigned long total_size;
+ unsigned long total_size, trailing;
if (!info || ! info->screen_base)
return -ENODEV;
@@ -808,10 +808,13 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
dst += c;
src += c;
- if (copy_to_user(buf, buffer, c)) {
+ trailing = copy_to_user(buf, buffer, c);
+ if (trailing == c) {
err = -EFAULT;
break;
}
+ c -= trailing;
+
*ppos += c;
buf += c;
cnt += c;
@@ -820,7 +823,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
kfree(buffer);
- return (err) ? err : cnt;
+ return cnt ? cnt : err;
}
static ssize_t
@@ -831,7 +834,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
u8 *buffer, *src;
u8 __iomem *dst;
int c, cnt = 0, err = 0;
- unsigned long total_size;
+ unsigned long total_size, trailing;
if (!info || !info->screen_base)
return -ENODEV;
@@ -876,10 +879,12 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
src = buffer;
- if (copy_from_user(src, buf, c)) {
+ trailing = copy_from_user(src, buf, c);
+ if (trailing == c) {
err = -EFAULT;
break;
}
+ c -= trailing;
fb_memcpy_tofb(dst, src, c);
dst += c;