git: e58ff66464ac - main - linux(4): Add a write syscall wrapper
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 20 Aug 2023 07:37:45 UTC
The branch main has been updated by dchagin: URL: https://cgit.FreeBSD.org/src/commit/?id=e58ff66464ac313296b683992c9131d7a85047de commit e58ff66464ac313296b683992c9131d7a85047de Author: Dmitry Chagin <dchagin@FreeBSD.org> AuthorDate: 2023-08-20 07:36:29 +0000 Commit: Dmitry Chagin <dchagin@FreeBSD.org> CommitDate: 2023-08-20 07:36:29 +0000 linux(4): Add a write syscall wrapper Adding a write syscall wrapper is needed due to Linux family of write syscalls doesn't distinguish between in kernel blocking operations and always returns EAGAIN while FreeBSD can return ENOBUFS. MFC after: 1 month --- sys/amd64/linux/linux_vdso_gtod.c | 2 +- sys/amd64/linux32/linux32_vdso_gtod.c | 2 +- sys/arm64/linux/linux_vdso_gtod.c | 2 +- sys/compat/linux/linux_file.c | 28 ++++++++++++++++++++++++++++ sys/compat/linux/linux_file.h | 4 ++++ sys/i386/linux/linux_vdso_gtod.c | 2 +- 6 files changed, 36 insertions(+), 4 deletions(-) diff --git a/sys/amd64/linux/linux_vdso_gtod.c b/sys/amd64/linux/linux_vdso_gtod.c index e2b5ebbec5ff..519ca2f2de93 100644 --- a/sys/amd64/linux/linux_vdso_gtod.c +++ b/sys/amd64/linux/linux_vdso_gtod.c @@ -61,7 +61,7 @@ write(int fd, const void *buf, size_t size) ( "syscall" : "=a"(res) - : "a"(LINUX_SYS_write), "D"(fd), "S"(buf), "d"(size) + : "a"(LINUX_SYS_linux_write), "D"(fd), "S"(buf), "d"(size) : "cc", "rcx", "r11", "memory" ); return (res); diff --git a/sys/amd64/linux32/linux32_vdso_gtod.c b/sys/amd64/linux32/linux32_vdso_gtod.c index 62e8dc3d3caf..ec5851c45c28 100644 --- a/sys/amd64/linux32/linux32_vdso_gtod.c +++ b/sys/amd64/linux32/linux32_vdso_gtod.c @@ -60,7 +60,7 @@ write(int fd, const void *buf, size_t size) ( "int $0x80" : "=a"(res) - : "a"(LINUX32_SYS_write), "b"(fd), "c"(buf), "d"(size) + : "a"(LINUX32_SYS_linux_write), "b"(fd), "c"(buf), "d"(size) : "cc", "memory" ); return (res); diff --git a/sys/arm64/linux/linux_vdso_gtod.c b/sys/arm64/linux/linux_vdso_gtod.c index 94a3c948d332..f7def68d88c4 100644 --- a/sys/arm64/linux/linux_vdso_gtod.c +++ b/sys/arm64/linux/linux_vdso_gtod.c @@ -50,7 +50,7 @@ uint32_t kern_tsc_selector = 0; static int write(int lfd, const void *lbuf, size_t lsize) { - register long svc asm("x8") = LINUX_SYS_write; + register long svc asm("x8") = LINUX_SYS_linux_write; register int fd asm("x0") = lfd; register const char *buf asm("x1") = lbuf; register long size asm("x2") = lsize; diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 62094697e107..6a1f61984b08 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -40,6 +40,7 @@ #include <sys/stat.h> #include <sys/sx.h> #include <sys/syscallsubr.h> +#include <sys/sysproto.h> #include <sys/tty.h> #include <sys/unistd.h> #include <sys/vnode.h> @@ -1827,3 +1828,30 @@ linux_close_range(struct thread *td, struct linux_close_range_args *args) flags |= CLOSE_RANGE_CLOEXEC; return (kern_close_range(td, flags, args->first, args->last)); } + +int +linux_enobufs2eagain(struct thread *td, int fd, int error) +{ + struct file *fp; + + if (error != ENOBUFS) + return (error); + if (fget(td, fd, &cap_no_rights, &fp) != 0) + return (error); + if (fp->f_type == DTYPE_SOCKET && (fp->f_flag & FNONBLOCK) != 0) + error = EAGAIN; + fdrop(fp, td); + return (error); +} + +int +linux_write(struct thread *td, struct linux_write_args *args) +{ + struct write_args bargs = { + .fd = args->fd, + .buf = args->buf, + .nbyte = args->nbyte, + }; + + return (linux_enobufs2eagain(td, args->fd, sys_write(td, &bargs))); +} diff --git a/sys/compat/linux/linux_file.h b/sys/compat/linux/linux_file.h index 0dcd7a5fd13e..ce9feca154ed 100644 --- a/sys/compat/linux/linux_file.h +++ b/sys/compat/linux/linux_file.h @@ -189,12 +189,16 @@ #define LINUX_HUGETLB_FLAG_ENCODE_2GB (31 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) #define LINUX_HUGETLB_FLAG_ENCODE_16GB (34U << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#if defined(_KERNEL) struct l_file_handle { l_uint handle_bytes; l_int handle_type; unsigned char f_handle[0]; }; +int linux_enobufs2eagain(struct thread *, int, int); +#endif + /* * Look at linux_close_range() for an explanation. * diff --git a/sys/i386/linux/linux_vdso_gtod.c b/sys/i386/linux/linux_vdso_gtod.c index 2147dbd3a0f8..ca200ce04da7 100644 --- a/sys/i386/linux/linux_vdso_gtod.c +++ b/sys/i386/linux/linux_vdso_gtod.c @@ -60,7 +60,7 @@ write(int fd, const void *buf, size_t size) ( "int $0x80" : "=a"(res) - : "a"(LINUX_SYS_write), "b"(fd), "c"(buf), "d"(size) + : "a"(LINUX_SYS_linux_write), "b"(fd), "c"(buf), "d"(size) : "cc", "memory" ); return (res);