The branch main has been updated by dchagin:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=e58ff66464ac313296b683992c9131d7a85047de

commit e58ff66464ac313296b683992c9131d7a85047de
Author:     Dmitry Chagin <dcha...@freebsd.org>
AuthorDate: 2023-08-20 07:36:29 +0000
Commit:     Dmitry Chagin <dcha...@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);

Reply via email to