Skip to content

Commit 921b738

Browse files
committed
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 6a2a886 ("[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
1 parent 254a4fd commit 921b738

2 files changed

Lines changed: 24 additions & 15 deletions

File tree

drivers/video/fbdev/core/fb_sys_fops.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count,
1919
unsigned long p = *ppos;
2020
void *src;
2121
int err = 0;
22-
unsigned long total_size;
22+
unsigned long total_size, c;
23+
ssize_t ret;
2324

2425
if (info->state != FBINFO_STATE_RUNNING)
2526
return -EPERM;
@@ -43,13 +44,14 @@ ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count,
4344
if (info->fbops->fb_sync)
4445
info->fbops->fb_sync(info);
4546

46-
if (copy_to_user(buf, src, count))
47+
c = copy_to_user(buf, src, count);
48+
if (c)
4749
err = -EFAULT;
50+
ret = count - c;
4851

49-
if (!err)
50-
*ppos += count;
52+
*ppos += ret;
5153

52-
return (err) ? err : count;
54+
return ret ? ret : err;
5355
}
5456
EXPORT_SYMBOL_GPL(fb_sys_read);
5557

@@ -59,7 +61,8 @@ ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
5961
unsigned long p = *ppos;
6062
void *dst;
6163
int err = 0;
62-
unsigned long total_size;
64+
unsigned long total_size, c;
65+
size_t ret;
6366

6467
if (info->state != FBINFO_STATE_RUNNING)
6568
return -EPERM;
@@ -89,13 +92,14 @@ ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
8992
if (info->fbops->fb_sync)
9093
info->fbops->fb_sync(info);
9194

92-
if (copy_from_user(dst, buf, count))
95+
c = copy_from_user(dst, buf, count);
96+
if (c)
9397
err = -EFAULT;
98+
ret = count - c;
9499

95-
if (!err)
96-
*ppos += count;
100+
*ppos += ret;
97101

98-
return (err) ? err : count;
102+
return ret ? ret : err;
99103
}
100104
EXPORT_SYMBOL_GPL(fb_sys_write);
101105

drivers/video/fbdev/core/fbmem.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
766766
u8 *buffer, *dst;
767767
u8 __iomem *src;
768768
int c, cnt = 0, err = 0;
769-
unsigned long total_size;
769+
unsigned long total_size, trailing;
770770

771771
if (!info || ! info->screen_base)
772772
return -ENODEV;
@@ -808,10 +808,13 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
808808
dst += c;
809809
src += c;
810810

811-
if (copy_to_user(buf, buffer, c)) {
811+
trailing = copy_to_user(buf, buffer, c);
812+
if (trailing == c) {
812813
err = -EFAULT;
813814
break;
814815
}
816+
c -= trailing;
817+
815818
*ppos += c;
816819
buf += c;
817820
cnt += c;
@@ -820,7 +823,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
820823

821824
kfree(buffer);
822825

823-
return (err) ? err : cnt;
826+
return cnt ? cnt : err;
824827
}
825828

826829
static ssize_t
@@ -831,7 +834,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
831834
u8 *buffer, *src;
832835
u8 __iomem *dst;
833836
int c, cnt = 0, err = 0;
834-
unsigned long total_size;
837+
unsigned long total_size, trailing;
835838

836839
if (!info || !info->screen_base)
837840
return -ENODEV;
@@ -876,10 +879,12 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
876879
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
877880
src = buffer;
878881

879-
if (copy_from_user(src, buf, c)) {
882+
trailing = copy_from_user(src, buf, c);
883+
if (trailing == c) {
880884
err = -EFAULT;
881885
break;
882886
}
887+
c -= trailing;
883888

884889
fb_memcpy_tofb(dst, src, c);
885890
dst += c;

0 commit comments

Comments
 (0)