This commit adds implementation of fanotify_init and fanotify_mark. Second argument for fanotify_init needs conversion because of flags which can be FAN_NONBLOCK and FAN_CLOEXEC which rely on O_NONBLOCK and O_CLOEXEC and those can have different values on different platforms. For fanotify_mark argument layout is different for 32-bit and 64-bit platforms and this implementation have support for that situation. Also, support for writing and reading of file descriptor opened by fanotify_init is added. Configure file contains checks for excistence of fanotify support on given build system.
Signed-off-by: Lena Djokic <lena.djo...@rt-rk.com> --- configure | 20 ++++++++ linux-user/syscall.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 142 insertions(+), 4 deletions(-) diff --git a/configure b/configure index fd6f898..56e6c98 100755 --- a/configure +++ b/configure @@ -3537,6 +3537,23 @@ if compile_prog "" "" ; then inotify1=yes fi +# check if fanotify group of system calls is supported +fanotify=no +cat > $TMPC << EOF +#include <sys/fanotify.h> + +int +main(void) +{ + fanotify_init(0,0); + fanotify_mark(0,0,0,0,0); + return 0; +} +EOF +if compile_prog "" "" ; then + fanotify=yes +fi + # check if utimensat and futimens are supported utimens=no cat > $TMPC << EOF @@ -5335,6 +5352,9 @@ fi if test "$inotify1" = "yes" ; then echo "CONFIG_INOTIFY1=y" >> $config_host_mak fi +if test "$fanotify" = "yes" ; then + echo "CONFIG_FANOTIFY=y" >> $config_host_mak +fi if test "$byteswap_h" = "yes" ; then echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak fi diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7b77503..f5d9a26 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -76,6 +76,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #ifdef CONFIG_SENDFILE #include <sys/sendfile.h> #endif +#ifdef CONFIG_FANOTIFY +#include <sys/fanotify.h> +#endif #define termios host_termios #define winsize host_winsize @@ -499,9 +502,13 @@ enum { QEMU___IFLA_INET6_MAX }; +typedef abi_long (*TargetFdReadFunc)(void *, size_t); +typedef abi_long (*TargetFdWriteFunc)(void *, size_t); typedef abi_long (*TargetFdDataFunc)(void *, size_t); typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t); typedef struct TargetFdTrans { + TargetFdReadFunc read_op; + TargetFdWriteFunc write_op; TargetFdDataFunc host_to_target_data; TargetFdDataFunc target_to_host_data; TargetFdAddrFunc target_to_host_addr; @@ -511,6 +518,22 @@ static TargetFdTrans **target_fd_trans; static unsigned int target_fd_max; +static TargetFdReadFunc fd_trans_read_op(int fd) +{ + if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) { + return target_fd_trans[fd]->read_op; + } + return NULL; +} + +static TargetFdWriteFunc fd_trans_write_op(int fd) +{ + if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) { + return target_fd_trans[fd]->write_op; + } + return NULL; +} + static TargetFdDataFunc fd_trans_target_to_host_data(int fd) { if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) { @@ -7527,6 +7550,47 @@ static target_timer_t get_timer_id(abi_long arg) return timerid; } +#if defined(CONFIG_FANOTIFY) +static inline abi_long fanotify_fd_read_op(void *buf, size_t len) +{ + struct fanotify_event_metadata *fem; + int num; + + /* Read buffer for fanotify file descriptor contains one or more + * of fanotify_event_metadata structures. + */ + fem = (struct fanotify_event_metadata *)buf; + num = len / sizeof(struct fanotify_event_metadata); + for (int i = 0; i < num; i++) { + (fem + i)->event_len = tswap32((fem + i)->event_len); + /* Fields (fem+i)->vers and (fem+i)->reserved are single byte, + * so swapping is not needed for them. + */ + (fem + i)->metadata_len = tswap16((fem + i)->metadata_len); + (fem + i)->mask = tswap64((fem + i)->mask); + (fem + i)->fd = tswap32((fem + i)->fd); + (fem + i)->pid = tswap32((fem + i)->pid); + } + + return len; +} + +static inline abi_long fanotify_fd_write_op(void *buf, size_t len) +{ + struct fanotify_response *fr = (struct fanotify_response *)buf; + + fr->fd = tswap32(fr->fd); + fr->response = tswap32(fr->response); + + return len; +} + +static TargetFdTrans fanotify_trans = { + .read_op = fanotify_fd_read_op, + .write_op = fanotify_fd_write_op, +}; +#endif + /* do_syscall() should always have a single exit point at the end so that actions, such as logging of syscall results, can be performed. All errnos that do_syscall() returns must be -TARGET_<errcode>. */ @@ -7613,16 +7677,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) goto efault; ret = get_errno(safe_read(arg1, p, arg3)); - if (ret >= 0 && - fd_trans_host_to_target_data(arg1)) { - ret = fd_trans_host_to_target_data(arg1)(p, ret); - } + if (ret >= 0) { + if (fd_trans_read_op(arg1)) { + ret = fd_trans_read_op(arg1)(p, ret); + } + if (fd_trans_host_to_target_data(arg1)) { + ret = fd_trans_host_to_target_data(arg1)(p, ret); + } + } unlock_user(p, arg2, ret); } break; case TARGET_NR_write: if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) goto efault; + if (fd_trans_write_op(arg1)) { + ret = fd_trans_write_op(arg1)(p, arg3); + if (is_error(ret)) { + unlock_user(p, arg2, 0); + break; + } + } ret = get_errno(safe_write(arg1, p, arg3)); unlock_user(p, arg2, 0); break; @@ -11567,6 +11642,49 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif +#if defined(TARGET_NR_fanotify_init) && defined(CONFIG_FANOTIFY) + case TARGET_NR_fanotify_init: + { + ret = get_errno(fanotify_init(arg1, target_to_host_bitmask(arg2, + fcntl_flags_tbl))); + if (ret >= 0) { + fd_trans_register(ret, &fanotify_trans); + } + } + break; +#endif +#if defined(TARGET_NR_fanotify_mark) && defined(CONFIG_FANOTIFY) + case TARGET_NR_fanotify_mark: + { + p = NULL; +#if (TARGET_ABI_BITS == 32) + if (arg6) { + p = lock_user_string(arg6); + if (!p) { + goto efault; + } + } + ret = get_errno(fanotify_mark(arg1, arg2, + target_offset64(arg3, arg4), arg5 , p)); + if (arg6) { + unlock_user(p, arg6, 0); + } +#else + if (arg5) { + p = lock_user_string(arg5); + if (!p) { + goto efault; + } + } + ret = get_errno(fanotify_mark(arg1, arg2, arg3, arg4 , p)); + if (arg5) { + unlock_user(p, arg5, 0); + } +#endif + } + break; +#endif + #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open) case TARGET_NR_mq_open: { -- 2.7.4