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);