From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43274) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VCQOG-0003VR-9c for qemu-devel@nongnu.org; Thu, 22 Aug 2013 04:37:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VCQO9-0005Hw-FH for qemu-devel@nongnu.org; Thu, 22 Aug 2013 04:37:11 -0400 Received: from mx1.redhat.com ([209.132.183.28]:17138) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VCQO9-0005Hm-7C for qemu-devel@nongnu.org; Thu, 22 Aug 2013 04:37:05 -0400 From: Stefan Hajnoczi Date: Thu, 22 Aug 2013 10:34:59 +0200 Message-Id: <1377160499-11323-3-git-send-email-stefanha@redhat.com> In-Reply-To: <1377160499-11323-1-git-send-email-stefanha@redhat.com> References: <1377160499-11323-1-git-send-email-stefanha@redhat.com> Subject: [Qemu-devel] [RFC 2/2] osdep: warn if opening a file O_DIRECT on tmpfs fails List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Kevin Wolf , Markus Armbruster , Stefan Hajnoczi , Deepak C Shetty Print a warning when opening a file O_DIRECT on tmpfs fails with EINVAL. This saves users a lot of time trying to figure out the EINVAL error. Reported-by: Deepak C Shetty Suggested-by: Eric Blake Suggested-by: Daniel P. Berrange Signed-off-by: Stefan Hajnoczi --- util/osdep.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/util/osdep.c b/util/osdep.c index 685c8ae..cbee2b7 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -148,6 +148,23 @@ static int qemu_parse_fdset(const char *param) #endif /* + * Open a file with O_CLOEXEC semantics + */ +static int open_cloexec(const char *name, int flags, int mode) +{ + int ret; +#ifdef O_CLOEXEC + ret = open(name, flags | O_CLOEXEC, mode); +#else + ret = open(name, flags, mode); + if (ret >= 0) { + qemu_set_cloexec(ret); + } +#endif + return ret; +} + +/* * Opens a file with FD_CLOEXEC set */ int qemu_open(const char *name, int flags, ...) @@ -198,14 +215,45 @@ int qemu_open(const char *name, int flags, ...) va_end(ap); } -#ifdef O_CLOEXEC - ret = open(name, flags | O_CLOEXEC, mode); -#else - ret = open(name, flags, mode); - if (ret >= 0) { - qemu_set_cloexec(ret); + /* Some file systems do not support O_DIRECT and fail with EINVAL. Confirm + * the problem by trying again without O_DIRECT and printing a warning. + * + * Sounds easy enough but we need to be careful with O_CREAT since this + * function should not create a file when an error is returned. + */ + if (flags & (O_CREAT | O_DIRECT) == O_CREAT | O_DIRECT) { + ret = open_cloexec(name, flags | O_EXCL, mode); + + if (ret >= 0) { + return ret; + } + + if (errno == EINVAL) { + error_report("file system may not support O_DIRECT"); + errno = EINVAL; /* in case it was clobbered */ + return ret; + } else if (errno == EEXIST && (flags & O_EXCL) == 0) { + /* We know the file existed, drop O_CREAT so the following open + * attempts do not create a file if O_DIRECT produces EINVAL. Note + * there is a race condition here if the file is deleted while we + * perform our open calls. + */ + flags &= O_CREAT; + } else { + return ret; + } + } + + ret = open_cloexec(name, flags, mode); + + if (ret == -1 && errno == EINVAL && (flags & O_DIRECT)) { + int fd = open_cloexec(name, flags & ~O_DIRECT, mode); + if (fd >= 0) { + close(fd); + error_report("file system does not support O_DIRECT"); + } + errno = EINVAL; /* in case it was clobbered */ } -#endif return ret; } -- 1.8.3.1