# include <linux/ioctl.h>
# include <linux/userfaultfd.h>
+# include "xlat/uffd_api_features.h"
# include "xlat/uffd_api_flags.h"
# include "xlat/uffd_copy_flags.h"
# include "xlat/uffd_register_ioctl_flags.h"
{
switch (code) {
case UFFDIO_API: {
+ uint64_t *entering_features;
struct uffdio_api ua;
+
if (entering(tcp)) {
tprints(", ");
if (umove_or_printaddr(tcp, arg, &ua))
- return RVAL_DECODED | 1;
- /* Features is intended to contain some flags, but
- * there aren't any defined yet.
- */
+ break;
PRINT_FIELD_X("{", ua, api);
- PRINT_FIELD_X(", ", ua, features);
- } else {
- if (!syserror(tcp) && !umove(tcp, arg, &ua)) {
- PRINT_FIELD_X(" => ", ua, features);
- PRINT_FIELD_FLAGS64(", ", ua, ioctls,
- uffd_api_flags,
- "_UFFDIO_???");
+ PRINT_FIELD_FLAGS(", ", ua, features, uffd_api_features,
+ "UFFD_FEATURE_???");
+ entering_features = malloc(sizeof(*entering_features));
+ if (entering_features) {
+ *entering_features = ua.features;
+ set_tcb_priv_data(tcp, entering_features, free);
+ }
+
+ return 0;
+ }
+
+ if (!syserror(tcp) && !umove(tcp, arg, &ua)) {
+ entering_features = get_tcb_priv_data(tcp);
+
+ if (!entering_features
+ || *entering_features != ua.features) {
+ PRINT_FIELD_FLAGS(" => ", ua, features,
+ uffd_api_features,
+ "UFFD_FEATURE_???");
}
- tprints("}");
+
+ PRINT_FIELD_FLAGS(", ", ua, ioctls, uffd_api_flags,
+ "_UFFDIO_???");
}
- return 1;
+
+ tprints("}");
+
+ break;
}
case UFFDIO_COPY: {
struct uffdio_copy uc;
+
if (entering(tcp)) {
tprints(", ");
if (umove_or_printaddr(tcp, arg, &uc))
- return RVAL_DECODED | 1;
+ return RVAL_IOCTL_DECODED;
PRINT_FIELD_X("{", uc, dst);
PRINT_FIELD_X(", ", uc, src);
PRINT_FIELD_X(", ", uc, len);
- PRINT_FIELD_FLAGS64(", ", uc, mode, uffd_copy_flags,
- "UFFDIO_COPY_???");
- } else {
- if (!syserror(tcp) && !umove(tcp, arg, &uc))
- PRINT_FIELD_X(", ", uc, copy);
- tprints("}");
+ PRINT_FIELD_FLAGS(", ", uc, mode, uffd_copy_flags,
+ "UFFDIO_COPY_???");
+
+ return 0;
}
- return 1;
+
+ if (!syserror(tcp) && !umove(tcp, arg, &uc))
+ PRINT_FIELD_X(", ", uc, copy);
+
+ tprints("}");
+
+ break;
}
case UFFDIO_REGISTER: {
struct uffdio_register ur;
+
if (entering(tcp)) {
tprints(", ");
if (umove_or_printaddr(tcp, arg, &ur))
- return RVAL_DECODED | 1;
+ return RVAL_IOCTL_DECODED;
PRINT_FIELD_UFFDIO_RANGE("{", ur, range);
- PRINT_FIELD_FLAGS64(", ", ur, mode,
- uffd_register_mode_flags,
- "UFFDIO_REGISTER_MODE_???");
- } else {
- if (!syserror(tcp) && !umove(tcp, arg, &ur)) {
- PRINT_FIELD_FLAGS64(", ", ur, ioctls,
- uffd_register_ioctl_flags,
- "UFFDIO_???");
- }
- tprints("}");
+ PRINT_FIELD_FLAGS(", ", ur, mode,
+ uffd_register_mode_flags,
+ "UFFDIO_REGISTER_MODE_???");
+
+ return 0;
+ }
+
+ if (!syserror(tcp) && !umove(tcp, arg, &ur)) {
+ PRINT_FIELD_FLAGS(", ", ur, ioctls,
+ uffd_register_ioctl_flags,
+ "UFFDIO_???");
}
- return 1;
+
+ tprints("}");
+
+ break;
}
case UFFDIO_UNREGISTER:
case UFFDIO_WAKE: {
struct uffdio_range ura;
+
tprints(", ");
+
if (!umove_or_printaddr(tcp, arg, &ura))
tprintf_uffdio_range(&ura);
- return RVAL_DECODED | 1;
+
+ break;
}
case UFFDIO_ZEROPAGE: {
struct uffdio_zeropage uz;
+
if (entering(tcp)) {
tprints(", ");
if (umove_or_printaddr(tcp, arg, &uz))
- return RVAL_DECODED | 1;
+ return RVAL_IOCTL_DECODED;
PRINT_FIELD_UFFDIO_RANGE("{", uz, range);
- PRINT_FIELD_FLAGS64(", ", uz, mode, uffd_zeropage_flags,
- "UFFDIO_ZEROPAGE_???");
- } else {
- if (!syserror(tcp) && !umove(tcp, arg, &uz))
- PRINT_FIELD_X(", ", uz, zeropage);
- tprints("}");
+ PRINT_FIELD_FLAGS(", ", uz, mode, uffd_zeropage_flags,
+ "UFFDIO_ZEROPAGE_???");
+
+ return 0;
}
- return 1;
+
+ if (!syserror(tcp) && !umove(tcp, arg, &uz))
+ PRINT_FIELD_X(", ", uz, zeropage);
+
+ tprints("}");
+
+ break;
}
default:
return RVAL_DECODED;
}
+
+ return RVAL_IOCTL_DECODED;
}
#endif /* HAVE_LINUX_USERFAULTFD_H */