lib: fdtable: Change ioctl vmethod signature to take va_list

As extend fdtable usage to more cases, there regularly arises a need
to forward ioctl/fcntl arguments to another ioctl vmethod, which is
complicated because it defined as taking variadic arguments. The only
portable solution is to convert variadic arguments to va_list at the
first point of entry from client code, and then pass va_list around.

To facilitate calling ioctl with variadic arguments from system code,
z_fdtable_call_ioctl() helper function is added.

Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This commit is contained in:
Paul Sokolovsky 2018-12-11 17:48:47 +03:00 committed by Jukka Rissanen
commit 13b38ed686
5 changed files with 59 additions and 54 deletions

View file

@ -6,6 +6,7 @@
#ifndef ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_
#define ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_
#include <stdarg.h>
#include <sys/types.h>
/* FIXME: For native_posix ssize_t, off_t. */
#include <fs.h>
@ -21,7 +22,7 @@ extern "C" {
struct fd_op_vtable {
ssize_t (*read)(void *obj, void *buf, size_t sz);
ssize_t (*write)(void *obj, const void *buf, size_t sz);
int (*ioctl)(void *obj, unsigned int request, ...);
int (*ioctl)(void *obj, unsigned int request, va_list args);
};
/**
@ -99,6 +100,31 @@ void *z_get_fd_obj(int fd, const struct fd_op_vtable *vtable, int err);
*/
void *z_get_fd_obj_and_vtable(int fd, const struct fd_op_vtable **vtable);
/**
* @brief Call ioctl vmethod on an object using varargs.
*
* We need this helper function because ioctl vmethod is declared to
* take va_list and the only portable way to construct va_list is from
* function's ... parameters.
*
* @param vtable vtable containing ioctl function pointer
* @param obj Object to call ioctl on
* @param request ioctl request number
* @param ... Variadic arguments to ioctl
*/
static inline int z_fdtable_call_ioctl(const struct fd_op_vtable *vtable, void *obj,
unsigned long request, ...)
{
va_list args;
int res;
va_start(args, request);
res = vtable->ioctl(obj, request, args);
va_end(args);
return res;
}
/**
* Request codes for fd_op_vtable.ioctl().
*

View file

@ -14,6 +14,7 @@
*/
#include <errno.h>
#include <fcntl.h>
#include <kernel.h>
#include <misc/fdtable.h>
@ -173,7 +174,7 @@ int close(int fd)
return -1;
}
res = fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_CLOSE);
res = z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_CLOSE);
z_free_fd(fd);
return res;
@ -181,16 +182,11 @@ int close(int fd)
int fsync(int fd)
{
int res;
if (_check_fd(fd) < 0) {
return -1;
}
res = fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_FSYNC);
z_free_fd(fd);
return res;
return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_FSYNC);
}
off_t lseek(int fd, off_t offset, int whence)
@ -199,8 +195,8 @@ off_t lseek(int fd, off_t offset, int whence)
return -1;
}
return fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_LSEEK,
offset, whence);
return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_LSEEK,
offset, whence);
}
/*
@ -225,7 +221,7 @@ static ssize_t stdinout_write_vmeth(void *obj, const void *buffer, size_t count)
#endif
}
static int stdinout_ioctl_vmeth(void *obj, unsigned int request, ...)
static int stdinout_ioctl_vmeth(void *obj, unsigned int request, va_list args)
{
errno = EINVAL;
return -1;

View file

@ -94,7 +94,7 @@ int open(const char *name, int flags)
return fd;
}
static int fs_ioctl_vmeth(void *obj, unsigned int request, ...)
static int fs_ioctl_vmeth(void *obj, unsigned int request, va_list args)
{
int rc;
struct posix_fs_desc *ptr = obj;
@ -105,14 +105,11 @@ static int fs_ioctl_vmeth(void *obj, unsigned int request, ...)
break;
case ZFD_IOCTL_LSEEK: {
va_list args;
off_t offset;
int whence;
va_start(args, request);
offset = va_arg(args, off_t);
whence = va_arg(args, int);
va_end(args);
rc = fs_seek(&ptr->file, offset, whence);
break;

View file

@ -157,8 +157,8 @@ int zsock_close_ctx(struct net_context *ctx)
int _impl_zsock_close(int sock)
{
const struct socket_op_vtable *vtable;
void *ctx = get_sock_vtable(sock, &vtable);
const struct fd_op_vtable *vtable;
void *ctx = z_get_fd_obj_and_vtable(sock, &vtable);
if (ctx == NULL) {
return -1;
@ -166,7 +166,7 @@ int _impl_zsock_close(int sock)
z_free_fd(sock);
return vtable->fd_vtable.ioctl(ctx, ZFD_IOCTL_CLOSE);
return z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_CLOSE);
}
#ifdef CONFIG_USERSPACE
@ -687,7 +687,15 @@ Z_SYSCALL_HANDLER(zsock_recvfrom, sock, buf, max_len, flags, src_addr,
*/
int _impl_zsock_fcntl(int sock, int cmd, int flags)
{
VTABLE_CALL(fd_vtable.ioctl, sock, cmd, flags);
const struct fd_op_vtable *vtable;
void *obj;
obj = z_get_fd_obj_and_vtable(sock, &vtable);
if (obj == NULL) {
return -1;
}
return z_fdtable_call_ioctl(vtable, obj, cmd, flags);
}
#ifdef CONFIG_USERSPACE
@ -755,7 +763,7 @@ int _impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout)
struct k_poll_event poll_events[CONFIG_NET_SOCKETS_POLL_MAX];
struct k_poll_event *pev;
struct k_poll_event *pev_end = poll_events + ARRAY_SIZE(poll_events);
const struct socket_op_vtable *vtable;
const struct fd_op_vtable *vtable;
u32_t entry_time = k_uptime_get_32();
if (timeout < 0) {
@ -771,14 +779,14 @@ int _impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout)
continue;
}
ctx = get_sock_vtable(pfd->fd, &vtable);
ctx = z_get_fd_obj_and_vtable(pfd->fd, &vtable);
if (ctx == NULL) {
/* Will set POLLNVAL in return loop */
continue;
}
if (vtable->fd_vtable.ioctl(ctx, ZFD_IOCTL_POLL_PREPARE,
pfd, &pev, pev_end) < 0) {
if (z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_PREPARE,
pfd, &pev, pev_end) < 0) {
if (errno == EALREADY) {
timeout = K_NO_WAIT;
continue;
@ -811,15 +819,15 @@ int _impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout)
continue;
}
ctx = get_sock_vtable(pfd->fd, &vtable);
ctx = z_get_fd_obj_and_vtable(pfd->fd, &vtable);
if (ctx == NULL) {
pfd->revents = ZSOCK_POLLNVAL;
ret++;
continue;
}
if (vtable->fd_vtable.ioctl(ctx, ZFD_IOCTL_POLL_UPDATE,
pfd, &pev) < 0) {
if (z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_UPDATE,
pfd, &pev) < 0) {
if (errno == EAGAIN) {
retry = true;
continue;
@ -958,7 +966,7 @@ static ssize_t sock_write_vmeth(void *obj, const void *buffer, size_t count)
return zsock_sendto_ctx(obj, buffer, count, 0, NULL, 0);
}
static int sock_ioctl_vmeth(void *obj, unsigned int request, ...)
static int sock_ioctl_vmeth(void *obj, unsigned int request, va_list args)
{
switch (request) {
@ -971,10 +979,8 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, ...)
return 0;
case F_SETFL: {
va_list args;
int flags;
va_start(args, request);
flags = va_arg(args, int);
if (flags & O_NONBLOCK) {
@ -990,29 +996,23 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, ...)
return zsock_close_ctx(obj);
case ZFD_IOCTL_POLL_PREPARE: {
va_list args;
struct zsock_pollfd *pfd;
struct k_poll_event **pev;
struct k_poll_event *pev_end;
va_start(args, request);
pfd = va_arg(args, struct zsock_pollfd *);
pev = va_arg(args, struct k_poll_event **);
pev_end = va_arg(args, struct k_poll_event *);
va_end(args);
return zsock_poll_prepare_ctx(obj, pfd, pev, pev_end);
}
case ZFD_IOCTL_POLL_UPDATE: {
va_list args;
struct zsock_pollfd *pfd;
struct k_poll_event **pev;
va_start(args, request);
pfd = va_arg(args, struct zsock_pollfd *);
pev = va_arg(args, struct k_poll_event **);
va_end(args);
return zsock_poll_update_ctx(obj, pfd, pev);
}

View file

@ -1180,7 +1180,7 @@ int ztls_close_ctx(struct net_context *ctx)
err = -EBADF;
}
ret = sock_fd_op_vtable.fd_vtable.ioctl(ctx, ZFD_IOCTL_CLOSE);
ret = z_fdtable_call_ioctl(&sock_fd_op_vtable.fd_vtable, ctx, ZFD_IOCTL_CLOSE);
/* In case close fails, we propagate errno value set by close.
* In case close succeeds, but tls_release fails, set errno
@ -1315,7 +1315,7 @@ error:
__ASSERT(err == 0, "TLS context release failed");
}
err = sock_fd_op_vtable.fd_vtable.ioctl(child, ZFD_IOCTL_CLOSE);
err = z_fdtable_call_ioctl(&sock_fd_op_vtable.fd_vtable, child, ZFD_IOCTL_CLOSE);
__ASSERT(err == 0, "Child socket close failed");
z_free_fd(fd);
@ -1849,51 +1849,37 @@ static ssize_t tls_sock_write_vmeth(void *obj, const void *buffer,
return ztls_sendto_ctx(obj, buffer, count, 0, NULL, 0);
}
static int tls_sock_ioctl_vmeth(void *obj, unsigned int request, ...)
static int tls_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args)
{
switch (request) {
/* fcntl() commands */
case F_GETFL:
case F_SETFL: {
va_list args;
int err;
case F_SETFL:
/* Pass the call to the core socket implementation. */
va_start(args, request);
err = sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args);
va_end(args);
return err;
}
return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args);
case ZFD_IOCTL_CLOSE:
return ztls_close_ctx(obj);
case ZFD_IOCTL_POLL_PREPARE: {
va_list args;
struct zsock_pollfd *pfd;
struct k_poll_event **pev;
struct k_poll_event *pev_end;
va_start(args, request);
pfd = va_arg(args, struct zsock_pollfd *);
pev = va_arg(args, struct k_poll_event **);
pev_end = va_arg(args, struct k_poll_event *);
va_end(args);
return ztls_poll_prepare_ctx(obj, pfd, pev, pev_end);
}
case ZFD_IOCTL_POLL_UPDATE: {
va_list args;
struct zsock_pollfd *pfd;
struct k_poll_event **pev;
va_start(args, request);
pfd = va_arg(args, struct zsock_pollfd *);
pev = va_arg(args, struct k_poll_event **);
va_end(args);
return ztls_poll_update_ctx(obj, pfd, pev);
}