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:
parent
89d270b28d
commit
e58ff66464
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user