Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Aug 2023 07:37:45 GMT
From:      Dmitry Chagin <dchagin@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: e58ff66464ac - main - linux(4): Add a write syscall wrapper
Message-ID:  <202308200737.37K7bjxW049604@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202308200737.37K7bjxW049604>