RFC userfaultfd ioctl decode
Dr. David Alan Gilbert
dgilbert at redhat.com
Fri Apr 22 14:55:43 UTC 2016
* Gabriel Laskar (gabriel at lse.epita.fr) wrote:
> On Thu, 21 Apr 2016 14:04:33 +0100
> "Dr. David Alan Gilbert" <dgilbert at redhat.com> wrote:
>
> > Hi,
> > Please find below a decoder for the UFFDIO_COPY ioctl
> > on the userfaultfd fd; but there are a few other ioctls
> > in the set to decode and I thought I'd ask before doing those:
> >
> > 1) Is it basically on the right lines; I'm not that confident
> > I understand the return flags on the ioctl decoder function.
>
> The return flags are the same as for the syscalls in general, it is
> written in defs.h around line 378. It allows to type the return value
> if it is not an int.
>
> For the ioctl decoding function, on entering there is:
>
> * 0 if nothing has been decoded, (and it will be probably done on
> exiting())
> * 1 parameter have been parsed, and printed
> * RVAL_DECODED if there is nothing else to do.
> * 1 | RVAL_DECODED : parameter have been parsed, but there is some kind
> of error/nothing has been printed, so this allow the ioctl decoder to
> write a default value.
>
> and on exiting, there is only 0 or 1.
Thanks; it would be great if one of these explanations went in ioctl.c
somewhere obvious.
> > 2) Are there any hooks for decoding data read off an fd? The
> > userfaultfd returns structures giving address of the fault etc.
>
> For the moment, there is no way to hook the read/write decoders in
> order to decode the buffers.
Pity, but OK.
> > Dave
> >
> >
> > >From a0f7d0e63a6d33a98d336b588830cd2dada649fc Mon Sep 17 00:00:00
> > >2001
> > From: "Dr. David Alan Gilbert" <dgilbert at redhat.com>
> > Date: Thu, 21 Apr 2016 13:49:40 +0100
> > Subject: [PATCH] Decode UFFDIO_COPY ioctl
> >
> > UFFDIO_COPY is one of the ioctls on the fd returned by userfaultfd.
> > Note that it reads from and also returns a result in it's data
> > structure.
> >
> > * configure.ac: Add test for userfaultfd.h.
> > * userfaultfd.c: Add ioctl decoder.
> > * defs.h: declare that decoder.
> > * ioctl.c: Wire in the new decoder.
> > ---
> > configure.ac | 3 +++
> > defs.h | 1 +
> > ioctl.c | 2 ++
> > userfaultfd.c | 41 +++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 47 insertions(+)
> >
> > diff --git a/configure.ac b/configure.ac
> > index 2b29c94..cb9b494 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -420,6 +420,9 @@ AC_CHECK_HEADERS([linux/input.h], [
> > AC_CHECK_MEMBERS([struct input_absinfo.resolution],,,
> > [#include <linux/input.h>]) ])
> >
> > +AC_CHECK_HEADERS([linux/userfaultfd.h], [
> > +])
>
> If there is no custom behavior to have for AC_CHECK_HEADERS, you can
> add the header to the global list.
Thanks, yes, done.
> > +
> > AC_CHECK_HEADERS([linux/bpf.h], [
> > AC_CACHE_CHECK([whether union bpf_attr.log_buf
> > initialization works], [st_cv_have_union_bpf_attr_log_buf],
> > diff --git a/defs.h b/defs.h
> > index ac59349..4894fdb 100644
> > --- a/defs.h
> > +++ b/defs.h
> > @@ -649,6 +649,7 @@ extern int scsi_ioctl(struct tcb *, const
> > unsigned int, long); extern int sock_ioctl(struct tcb *, const
> > unsigned int, long); extern int term_ioctl(struct tcb *, const
> > unsigned int, long); extern int ubi_ioctl(struct tcb *, const
> > unsigned int, long); +extern int uffdio_ioctl(struct tcb *, const
> > unsigned int, long); extern int v4l2_ioctl(struct tcb *, const
> > unsigned int, long);
> > extern int tv_nz(const struct timeval *);
> > diff --git a/ioctl.c b/ioctl.c
> > index f70dc44..464329b 100644
> > --- a/ioctl.c
> > +++ b/ioctl.c
> > @@ -263,6 +263,8 @@ ioctl_decode(struct tcb *tcp)
> > case 'E':
> > return evdev_ioctl(tcp, code, arg);
> > #endif
> > + case 0xaa:
> > + return uffdio_ioctl(tcp, code, arg);
>
> for most of the ioctl code, we prefer to have the #ifdef HEADER around
> the case instead of inside the function, but this is mostly cosmetic
> and for consistence.
Yes, done.
>
> > default:
> > break;
> > }
> > diff --git a/userfaultfd.c b/userfaultfd.c
> > index 15f825a..2a06e1f 100644
> > --- a/userfaultfd.c
> > +++ b/userfaultfd.c
> > @@ -27,9 +27,50 @@
> >
> > #include "defs.h"
> > #include <fcntl.h>
> > +#include <linux/ioctl.h>
> > +#ifdef HAVE_LINUX_USERFAULTFD_H
> > +#include <linux/userfaultfd.h>
> > +#endif
> >
> > #include "xlat/uffd_flags.h"
> >
> > +
> > +int
> > +uffdio_ioctl(struct tcb *tcp, const unsigned int code, const long
> > arg) +{
> > +#ifdef HAVE_LINUX_USERFAULTFD_H
> > + static char auxbuf[64];
> > +#endif
> > +
> > + switch (code) {
> > +#ifdef HAVE_LINUX_USERFAULTFD_H
> > + case UFFDIO_COPY: {
>
> before that, you need to check
>
> > + struct uffdio_copy uc;
> > + if (!umove_or_printaddr(tcp, arg, &uc)) {
> > + if (entering(tcp)) {
> > + tprintf("{dst=%" PRIx64 ", src=%"
> > PRIx64
> > + ", len=%" PRIu64 ", mode=%" PRIu64
> > "}",
> > + (uint64_t)uc.dst, (uint64_t)uc.src,
> > + (uint64_t)uc.len, (uint64_t)uc.mode);
> > + return 1;
> > + } else {
> > + /* copy also returns the number of
> > bytes
> > + * copied */
> > + sprintf(auxbuf, "copy=%" PRId64,
> > + (int64_t)uc.copy);
> > + tcp->auxstr = auxbuf;
> > + return RVAL_STR | 1;
>
> There is no need to do anything on exit. The return value as an int is
> fine.
Thanks, yes, similar to Dmitry's comments.
Thanks again,
Dave
> > + }
> > + }
> > + break;
> > + }
> > +#endif
> > +
> > + default:
> > + return 0;
> > + }
> > +}
> > +
> > SYS_FUNC(userfaultfd)
> > {
> > printflags(uffd_flags, tcp->u_arg[0], "UFFD_???");
>
>
>
> --
> Gabriel Laskar
--
Dr. David Alan Gilbert / dgilbert at redhat.com / Manchester, UK
More information about the Strace-devel
mailing list