linuxulator: implement sendfile
Submitted by: Bora Özarslan <borako.ozarslan@gmail.com> Submitted by: Yang Wang <2333@outlook.jp> Reviewed by: markj Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D19917
This commit is contained in:
parent
4c3d743519
commit
77a92d8644
@ -59,7 +59,6 @@ UNIMPLEMENTED(set_thread_area);
|
||||
UNIMPLEMENTED(uselib);
|
||||
UNIMPLEMENTED(vserver);
|
||||
|
||||
DUMMY(sendfile);
|
||||
DUMMY(setfsuid);
|
||||
DUMMY(setfsgid);
|
||||
DUMMY(sysfs);
|
||||
|
@ -72,7 +72,6 @@ DUMMY(delete_module);
|
||||
DUMMY(quotactl);
|
||||
DUMMY(bdflush);
|
||||
DUMMY(sysfs);
|
||||
DUMMY(sendfile);
|
||||
DUMMY(setfsuid);
|
||||
DUMMY(setfsgid);
|
||||
DUMMY(pivot_root);
|
||||
|
@ -338,7 +338,8 @@
|
||||
struct l_user_cap_data *datap); }
|
||||
186 AUE_NULL STD { int linux_sigaltstack(l_stack_t *uss, \
|
||||
l_stack_t *uoss); }
|
||||
187 AUE_SENDFILE STD { int linux_sendfile(void); }
|
||||
187 AUE_SENDFILE STD { int linux_sendfile(l_int out, l_int in, \
|
||||
l_long *offset, l_size_t count); }
|
||||
188 AUE_GETPMSG UNIMPL getpmsg
|
||||
189 AUE_PUTPMSG UNIMPL putpmsg
|
||||
190 AUE_VFORK STD { int linux_vfork(void); }
|
||||
@ -412,7 +413,8 @@
|
||||
236 AUE_NULL STD { int linux_lremovexattr(void); }
|
||||
237 AUE_NULL STD { int linux_fremovexattr(void); }
|
||||
238 AUE_NULL STD { int linux_tkill(int tid, int sig); }
|
||||
239 AUE_SENDFILE UNIMPL linux_sendfile64
|
||||
239 AUE_SENDFILE STD { int linux_sendfile64(l_int out, l_int in, \
|
||||
l_loff_t *offset, l_size_t count); }
|
||||
240 AUE_NULL STD { int linux_sys_futex(void *uaddr, int op, uint32_t val, \
|
||||
struct l_timespec *timeout, uint32_t *uaddr2, uint32_t val3); }
|
||||
241 AUE_NULL STD { int linux_sched_setaffinity(l_pid_t pid, l_uint len, \
|
||||
|
@ -868,7 +868,12 @@
|
||||
);
|
||||
}
|
||||
187 AUE_SENDFILE STD {
|
||||
int linux_sendfile(void);
|
||||
int linux_sendfile(
|
||||
l_int out,
|
||||
l_int in,
|
||||
l_long *offset,
|
||||
l_size_t count
|
||||
);
|
||||
}
|
||||
188 AUE_NULL UNIMPL ; was getpmsg
|
||||
189 AUE_NULL UNIMPL ; was putpmsg
|
||||
@ -1090,7 +1095,14 @@
|
||||
int sig
|
||||
);
|
||||
}
|
||||
239 AUE_SENDFILE UNIMPL linux_sendfile64
|
||||
239 AUE_SENDFILE STD {
|
||||
int linux_sendfile64(
|
||||
l_int out,
|
||||
l_int in,
|
||||
l_loff_t *offset,
|
||||
l_size_t count
|
||||
);
|
||||
}
|
||||
240 AUE_NULL STD {
|
||||
int linux_sys_futex(void *uaddr,
|
||||
int op,
|
||||
|
@ -64,7 +64,6 @@ UNIMPLEMENTED(tuxcall);
|
||||
UNIMPLEMENTED(uselib);
|
||||
UNIMPLEMENTED(vserver);
|
||||
|
||||
DUMMY(sendfile);
|
||||
DUMMY(setfsuid);
|
||||
DUMMY(setfsgid);
|
||||
DUMMY(vhangup);
|
||||
|
@ -49,8 +49,12 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#include <security/audit/audit.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/vnet.h>
|
||||
@ -1581,7 +1585,134 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
|
||||
static int
|
||||
linux_sendfile_common(struct thread *td, l_int out, l_int in,
|
||||
l_loff_t *offset, l_size_t count)
|
||||
{
|
||||
off_t bytes_read;
|
||||
int error;
|
||||
l_loff_t current_offset;
|
||||
struct file *fp;
|
||||
|
||||
AUDIT_ARG_FD(in);
|
||||
error = fget_read(td, in, &cap_pread_rights, &fp);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
if (offset != NULL) {
|
||||
current_offset = *offset;
|
||||
} else {
|
||||
error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ?
|
||||
fo_seek(fp, 0, SEEK_CUR, td) : ESPIPE;
|
||||
if (error != 0)
|
||||
goto drop;
|
||||
current_offset = td->td_uretoff.tdu_off;
|
||||
}
|
||||
|
||||
bytes_read = 0;
|
||||
|
||||
/* Linux cannot have 0 count. */
|
||||
if (count <= 0 || current_offset < 0) {
|
||||
error = EINVAL;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
error = fo_sendfile(fp, out, NULL, NULL, current_offset, count,
|
||||
&bytes_read, 0, td);
|
||||
if (error != 0)
|
||||
goto drop;
|
||||
current_offset += bytes_read;
|
||||
|
||||
if (offset != NULL) {
|
||||
*offset = current_offset;
|
||||
} else {
|
||||
error = fo_seek(fp, current_offset, SEEK_SET, td);
|
||||
if (error != 0)
|
||||
goto drop;
|
||||
}
|
||||
|
||||
td->td_retval[0] = (ssize_t)bytes_read;
|
||||
drop:
|
||||
fdrop(fp, td);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_sendfile(struct thread *td, struct linux_sendfile_args *arg)
|
||||
{
|
||||
/*
|
||||
* Differences between FreeBSD and Linux sendfile:
|
||||
* - Linux doesn't send anything when count is 0 (FreeBSD uses 0 to
|
||||
* mean send the whole file.) In linux_sendfile given fds are still
|
||||
* checked for validity when the count is 0.
|
||||
* - Linux can send to any fd whereas FreeBSD only supports sockets.
|
||||
* The same restriction follows for linux_sendfile.
|
||||
* - Linux doesn't have an equivalent for FreeBSD's flags and sf_hdtr.
|
||||
* - Linux takes an offset pointer and updates it to the read location.
|
||||
* FreeBSD takes in an offset and a 'bytes read' parameter which is
|
||||
* only filled if it isn't NULL. We use this parameter to update the
|
||||
* offset pointer if it exists.
|
||||
* - Linux sendfile returns bytes read on success while FreeBSD
|
||||
* returns 0. We use the 'bytes read' parameter to get this value.
|
||||
*/
|
||||
|
||||
l_loff_t offset64;
|
||||
l_long offset;
|
||||
int ret;
|
||||
int error;
|
||||
|
||||
if (arg->offset != NULL) {
|
||||
error = copyin(arg->offset, &offset, sizeof(offset));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
offset64 = (l_loff_t)offset;
|
||||
}
|
||||
|
||||
ret = linux_sendfile_common(td, arg->out, arg->in,
|
||||
arg->offset != NULL ? &offset64 : NULL, arg->count);
|
||||
|
||||
if (arg->offset != NULL) {
|
||||
#if defined(__i386__) || defined(__arm__) || \
|
||||
(defined(__amd64__) && defined(COMPAT_LINUX32))
|
||||
if (offset64 > INT32_MAX)
|
||||
return (EOVERFLOW);
|
||||
#endif
|
||||
offset = (l_long)offset64;
|
||||
error = copyout(&offset, arg->offset, sizeof(offset));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__arm__) || \
|
||||
(defined(__amd64__) && defined(COMPAT_LINUX32))
|
||||
|
||||
int
|
||||
linux_sendfile64(struct thread *td, struct linux_sendfile64_args *arg)
|
||||
{
|
||||
l_loff_t offset;
|
||||
int ret;
|
||||
int error;
|
||||
|
||||
if (arg->offset != NULL) {
|
||||
error = copyin(arg->offset, &offset, sizeof(offset));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
|
||||
ret = linux_sendfile_common(td, arg->out, arg->in,
|
||||
arg->offset != NULL ? &offset : NULL, arg->count);
|
||||
|
||||
if (arg->offset != NULL) {
|
||||
error = copyout(&offset, arg->offset, sizeof(offset));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Argument list sizes for linux_socketcall */
|
||||
static const unsigned char lxs_args_cnt[] = {
|
||||
@ -1595,7 +1726,7 @@ static const unsigned char lxs_args_cnt[] = {
|
||||
5 /* setsockopt */, 5 /* getsockopt */,
|
||||
3 /* sendmsg */, 3 /* recvmsg */,
|
||||
4 /* accept4 */, 5 /* recvmmsg */,
|
||||
4 /* sendmmsg */
|
||||
4 /* sendmmsg */, 4 /* sendfile */
|
||||
};
|
||||
#define LINUX_ARGS_CNT (nitems(lxs_args_cnt) - 1)
|
||||
#define LINUX_ARG_SIZE(x) (lxs_args_cnt[x] * sizeof(l_ulong))
|
||||
@ -1664,9 +1795,11 @@ linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
|
||||
return (linux_recvmmsg(td, arg));
|
||||
case LINUX_SENDMMSG:
|
||||
return (linux_sendmmsg(td, arg));
|
||||
case LINUX_SENDFILE:
|
||||
return (linux_sendfile(td, arg));
|
||||
}
|
||||
|
||||
uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
|
||||
return (ENOSYS);
|
||||
}
|
||||
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
|
||||
#endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */
|
||||
|
@ -132,7 +132,9 @@ struct l_ucred {
|
||||
uint32_t gid;
|
||||
};
|
||||
|
||||
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
|
||||
#if defined(__i386__) || defined(__arm__) || \
|
||||
(defined(__amd64__) && defined(COMPAT_LINUX32))
|
||||
|
||||
struct linux_accept_args {
|
||||
register_t s;
|
||||
register_t addr;
|
||||
@ -162,7 +164,9 @@ int linux_accept(struct thread *td, struct linux_accept_args *args);
|
||||
#define LINUX_ACCEPT4 18
|
||||
#define LINUX_RECVMMSG 19
|
||||
#define LINUX_SENDMMSG 20
|
||||
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
|
||||
#define LINUX_SENDFILE 21
|
||||
|
||||
#endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */
|
||||
|
||||
/* Socket defines */
|
||||
#define LINUX_SOL_SOCKET 1
|
||||
|
@ -75,7 +75,6 @@ DUMMY(quotactl);
|
||||
DUMMY(bdflush);
|
||||
DUMMY(sysfs);
|
||||
DUMMY(vm86);
|
||||
DUMMY(sendfile); /* different semantics */
|
||||
DUMMY(setfsuid);
|
||||
DUMMY(setfsgid);
|
||||
DUMMY(pivot_root);
|
||||
|
@ -341,7 +341,8 @@
|
||||
struct l_user_cap_data *datap); }
|
||||
186 AUE_NULL STD { int linux_sigaltstack(l_stack_t *uss, \
|
||||
l_stack_t *uoss); }
|
||||
187 AUE_SENDFILE STD { int linux_sendfile(void); }
|
||||
187 AUE_SENDFILE STD { int linux_sendfile(l_int out, l_int in, \
|
||||
l_long *offset, l_size_t count); }
|
||||
188 AUE_GETPMSG UNIMPL getpmsg
|
||||
189 AUE_PUTPMSG UNIMPL putpmsg
|
||||
190 AUE_VFORK STD { int linux_vfork(void); }
|
||||
@ -415,7 +416,8 @@
|
||||
236 AUE_NULL STD { int linux_lremovexattr(void); }
|
||||
237 AUE_NULL STD { int linux_fremovexattr(void); }
|
||||
238 AUE_NULL STD { int linux_tkill(int tid, int sig); }
|
||||
239 AUE_SENDFILE UNIMPL linux_sendfile64
|
||||
239 AUE_SENDFILE STD { int linux_sendfile64(l_int out, l_int in, \
|
||||
l_loff_t *offset, l_size_t count); }
|
||||
240 AUE_NULL STD { int linux_sys_futex(void *uaddr, int op, uint32_t val, \
|
||||
struct l_timespec *timeout, uint32_t *uaddr2, uint32_t val3); }
|
||||
241 AUE_NULL STD { int linux_sched_setaffinity(l_pid_t pid, l_uint len, \
|
||||
|
Loading…
Reference in New Issue
Block a user