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
This commit is contained in:
Dmitry Chagin 2023-08-20 10:36:29 +03:00
parent 89d270b28d
commit e58ff66464
6 changed files with 36 additions and 4 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
*

View File

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