diff --git a/tools/include/xen-sys/Linux/privcmd.h b/tools/include/xen-sys/Linux/privcmd.h index 9531b728f9..bc60e8fd55 100644 --- a/tools/include/xen-sys/Linux/privcmd.h +++ b/tools/include/xen-sys/Linux/privcmd.h @@ -114,5 +114,7 @@ typedef struct privcmd_mmap_resource { _IOC(_IOC_NONE, 'P', 6, sizeof(domid_t)) #define IOCTL_PRIVCMD_MMAP_RESOURCE \ _IOC(_IOC_NONE, 'P', 7, sizeof(privcmd_mmap_resource_t)) +#define IOCTL_PRIVCMD_UNIMPLEMENTED \ + _IOC(_IOC_NONE, 'P', 0xFF, 0) #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */ diff --git a/tools/libs/foreignmemory/linux.c b/tools/libs/foreignmemory/linux.c index 3686cf41e0..0368aa09f4 100644 --- a/tools/libs/foreignmemory/linux.c +++ b/tools/libs/foreignmemory/linux.c @@ -53,6 +53,23 @@ int osdep_xenforeignmemory_open(xenforeignmemory_handle *fmem) return -1; } + /* + * Older versions of privcmd return -EINVAL for unimplemented ioctls + * so we need to probe for the errno to use rather than just using + * the conventional ENOTTY. + */ + if ( ioctl(fd, IOCTL_PRIVCMD_UNIMPLEMENTED, NULL) >= 0 ) + { + xtl_log(fmem->logger, XTL_ERROR, -1, "xenforeignmemory", + "privcmd ioctl should not be implemented"); + return -1; + } + else + { + fmem->unimpl_errno = errno; + errno = 0; + } + fmem->fd = fd; return 0; } @@ -307,7 +324,7 @@ int osdep_xenforeignmemory_map_resource( { int saved_errno; - if ( errno != ENOTTY && errno != EOPNOTSUPP ) + if ( errno != fmem->unimpl_errno && errno != EOPNOTSUPP ) PERROR("ioctl failed"); else errno = EOPNOTSUPP; diff --git a/tools/libs/foreignmemory/private.h b/tools/libs/foreignmemory/private.h index b06ce12583..8f1bf081ed 100644 --- a/tools/libs/foreignmemory/private.h +++ b/tools/libs/foreignmemory/private.h @@ -23,6 +23,7 @@ struct xenforeignmemory_handle { unsigned flags; int fd; Xentoolcore__Active_Handle tc_ah; + int unimpl_errno; }; int osdep_xenforeignmemory_open(xenforeignmemory_handle *fmem);