|
|
f954f3 |
From 5bd332a683811586039f99f31c01d4f2f7181334 Mon Sep 17 00:00:00 2001
|
|
|
f954f3 |
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
|
f954f3 |
Date: Mon, 26 Jul 2021 15:21:18 +0100
|
|
|
f954f3 |
Subject: [PATCH] cache, cow: Use full pread/pwrite operations
|
|
|
f954f3 |
|
|
|
f954f3 |
Although it probably cannot happen on Linux, POSIX allows pread/pwrite
|
|
|
f954f3 |
to return or write fewer bytes than requested. The cache and cow
|
|
|
f954f3 |
filters didn't handle this situation. Replace the raw
|
|
|
f954f3 |
pread(2)/pwrite(2) syscalls with alternate versions which can handle
|
|
|
f954f3 |
this.
|
|
|
f954f3 |
|
|
|
f954f3 |
(cherry picked from commit ce0db9d7736dd28dd0f10951ce65853e50b35e41)
|
|
|
f954f3 |
---
|
|
|
f954f3 |
common/utils/Makefile.am | 1 +
|
|
|
f954f3 |
common/utils/full-rw.c | 81 ++++++++++++++++++++++++++++++++++++++++
|
|
|
f954f3 |
common/utils/utils.h | 2 +
|
|
|
f954f3 |
filters/cache/blk.c | 10 ++---
|
|
|
f954f3 |
filters/cow/blk.c | 6 +--
|
|
|
f954f3 |
5 files changed, 92 insertions(+), 8 deletions(-)
|
|
|
f954f3 |
create mode 100644 common/utils/full-rw.c
|
|
|
f954f3 |
|
|
|
f954f3 |
diff --git a/common/utils/Makefile.am b/common/utils/Makefile.am
|
|
|
f954f3 |
index 1708a4c8..14e9dfc4 100644
|
|
|
f954f3 |
--- a/common/utils/Makefile.am
|
|
|
f954f3 |
+++ b/common/utils/Makefile.am
|
|
|
f954f3 |
@@ -40,6 +40,7 @@ libutils_la_SOURCES = \
|
|
|
f954f3 |
cleanup-nbdkit.c \
|
|
|
f954f3 |
cleanup.h \
|
|
|
f954f3 |
environ.c \
|
|
|
f954f3 |
+ full-rw.c \
|
|
|
f954f3 |
quote.c \
|
|
|
f954f3 |
utils.c \
|
|
|
f954f3 |
utils.h \
|
|
|
f954f3 |
diff --git a/common/utils/full-rw.c b/common/utils/full-rw.c
|
|
|
f954f3 |
new file mode 100644
|
|
|
f954f3 |
index 00000000..55b32cdd
|
|
|
f954f3 |
--- /dev/null
|
|
|
f954f3 |
+++ b/common/utils/full-rw.c
|
|
|
f954f3 |
@@ -0,0 +1,81 @@
|
|
|
f954f3 |
+/* nbdkit
|
|
|
f954f3 |
+ * Copyright (C) 2021 Red Hat Inc.
|
|
|
f954f3 |
+ *
|
|
|
f954f3 |
+ * Redistribution and use in source and binary forms, with or without
|
|
|
f954f3 |
+ * modification, are permitted provided that the following conditions are
|
|
|
f954f3 |
+ * met:
|
|
|
f954f3 |
+ *
|
|
|
f954f3 |
+ * * Redistributions of source code must retain the above copyright
|
|
|
f954f3 |
+ * notice, this list of conditions and the following disclaimer.
|
|
|
f954f3 |
+ *
|
|
|
f954f3 |
+ * * Redistributions in binary form must reproduce the above copyright
|
|
|
f954f3 |
+ * notice, this list of conditions and the following disclaimer in the
|
|
|
f954f3 |
+ * documentation and/or other materials provided with the distribution.
|
|
|
f954f3 |
+ *
|
|
|
f954f3 |
+ * * Neither the name of Red Hat nor the names of its contributors may be
|
|
|
f954f3 |
+ * used to endorse or promote products derived from this software without
|
|
|
f954f3 |
+ * specific prior written permission.
|
|
|
f954f3 |
+ *
|
|
|
f954f3 |
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
|
|
|
f954f3 |
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
|
f954f3 |
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
|
f954f3 |
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
|
|
|
f954f3 |
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
f954f3 |
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
f954f3 |
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
|
f954f3 |
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
f954f3 |
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
f954f3 |
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
|
f954f3 |
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
f954f3 |
+ * SUCH DAMAGE.
|
|
|
f954f3 |
+ */
|
|
|
f954f3 |
+
|
|
|
f954f3 |
+/* These functions are like pread(2)/pwrite(2) but they always read or
|
|
|
f954f3 |
+ * write the full amount, or fail.
|
|
|
f954f3 |
+ */
|
|
|
f954f3 |
+
|
|
|
f954f3 |
+#include <config.h>
|
|
|
f954f3 |
+
|
|
|
f954f3 |
+#include <stdio.h>
|
|
|
f954f3 |
+#include <stdlib.h>
|
|
|
f954f3 |
+#include <unistd.h>
|
|
|
f954f3 |
+#include <errno.h>
|
|
|
f954f3 |
+
|
|
|
f954f3 |
+ssize_t
|
|
|
f954f3 |
+full_pread (int fd, void *buf, size_t count, off_t offset)
|
|
|
f954f3 |
+{
|
|
|
f954f3 |
+ ssize_t ret = 0, r;
|
|
|
f954f3 |
+
|
|
|
f954f3 |
+ while (count > 0) {
|
|
|
f954f3 |
+ r = pread (fd, buf, count, offset);
|
|
|
f954f3 |
+ if (r == -1) return -1;
|
|
|
f954f3 |
+ if (r == 0) {
|
|
|
f954f3 |
+ /* Presumably the caller wasn't expecting end-of-file here, so
|
|
|
f954f3 |
+ * return an error.
|
|
|
f954f3 |
+ */
|
|
|
f954f3 |
+ errno = EIO;
|
|
|
f954f3 |
+ return -1;
|
|
|
f954f3 |
+ }
|
|
|
f954f3 |
+ ret += r;
|
|
|
f954f3 |
+ offset += r;
|
|
|
f954f3 |
+ count -= r;
|
|
|
f954f3 |
+ }
|
|
|
f954f3 |
+
|
|
|
f954f3 |
+ return ret;
|
|
|
f954f3 |
+}
|
|
|
f954f3 |
+
|
|
|
f954f3 |
+ssize_t
|
|
|
f954f3 |
+full_pwrite (int fd, const void *buf, size_t count, off_t offset)
|
|
|
f954f3 |
+{
|
|
|
f954f3 |
+ ssize_t ret = 0, r;
|
|
|
f954f3 |
+
|
|
|
f954f3 |
+ while (count > 0) {
|
|
|
f954f3 |
+ r = pwrite (fd, buf, count, offset);
|
|
|
f954f3 |
+ if (r == -1) return -1;
|
|
|
f954f3 |
+ ret += r;
|
|
|
f954f3 |
+ offset += r;
|
|
|
f954f3 |
+ count -= r;
|
|
|
f954f3 |
+ }
|
|
|
f954f3 |
+
|
|
|
f954f3 |
+ return ret;
|
|
|
f954f3 |
+}
|
|
|
f954f3 |
diff --git a/common/utils/utils.h b/common/utils/utils.h
|
|
|
f954f3 |
index f8f70212..83397ae1 100644
|
|
|
f954f3 |
--- a/common/utils/utils.h
|
|
|
f954f3 |
+++ b/common/utils/utils.h
|
|
|
f954f3 |
@@ -40,5 +40,7 @@ extern int set_cloexec (int fd);
|
|
|
f954f3 |
extern int set_nonblock (int fd);
|
|
|
f954f3 |
extern char **copy_environ (char **env, ...) __attribute__((__sentinel__));
|
|
|
f954f3 |
extern char *make_temporary_directory (void);
|
|
|
f954f3 |
+extern ssize_t full_pread (int fd, void *buf, size_t count, off_t offset);
|
|
|
f954f3 |
+extern ssize_t full_pwrite (int fd, const void *buf, size_t count, off_t offset);
|
|
|
f954f3 |
|
|
|
f954f3 |
#endif /* NBDKIT_UTILS_H */
|
|
|
f954f3 |
diff --git a/filters/cache/blk.c b/filters/cache/blk.c
|
|
|
f954f3 |
index f85ada35..42bd3779 100644
|
|
|
f954f3 |
--- a/filters/cache/blk.c
|
|
|
f954f3 |
+++ b/filters/cache/blk.c
|
|
|
f954f3 |
@@ -250,7 +250,7 @@ _blk_read_multiple (nbdkit_next *next,
|
|
|
f954f3 |
" (offset %" PRIu64 ")",
|
|
|
f954f3 |
blknum, (uint64_t) offset);
|
|
|
f954f3 |
|
|
|
f954f3 |
- if (pwrite (fd, block, blksize * runblocks, offset) == -1) {
|
|
|
f954f3 |
+ if (full_pwrite (fd, block, blksize * runblocks, offset) == -1) {
|
|
|
f954f3 |
*err = errno;
|
|
|
f954f3 |
nbdkit_error ("pwrite: %m");
|
|
|
f954f3 |
return -1;
|
|
|
f954f3 |
@@ -262,7 +262,7 @@ _blk_read_multiple (nbdkit_next *next,
|
|
|
f954f3 |
}
|
|
|
f954f3 |
}
|
|
|
f954f3 |
else { /* Read cache. */
|
|
|
f954f3 |
- if (pread (fd, block, blksize * runblocks, offset) == -1) {
|
|
|
f954f3 |
+ if (full_pread (fd, block, blksize * runblocks, offset) == -1) {
|
|
|
f954f3 |
*err = errno;
|
|
|
f954f3 |
nbdkit_error ("pread: %m");
|
|
|
f954f3 |
return -1;
|
|
|
f954f3 |
@@ -339,7 +339,7 @@ blk_cache (nbdkit_next *next,
|
|
|
f954f3 |
nbdkit_debug ("cache: cache block %" PRIu64 " (offset %" PRIu64 ")",
|
|
|
f954f3 |
blknum, (uint64_t) offset);
|
|
|
f954f3 |
|
|
|
f954f3 |
- if (pwrite (fd, block, blksize, offset) == -1) {
|
|
|
f954f3 |
+ if (full_pwrite (fd, block, blksize, offset) == -1) {
|
|
|
f954f3 |
*err = errno;
|
|
|
f954f3 |
nbdkit_error ("pwrite: %m");
|
|
|
f954f3 |
return -1;
|
|
|
f954f3 |
@@ -380,7 +380,7 @@ blk_writethrough (nbdkit_next *next,
|
|
|
f954f3 |
nbdkit_debug ("cache: writethrough block %" PRIu64 " (offset %" PRIu64 ")",
|
|
|
f954f3 |
blknum, (uint64_t) offset);
|
|
|
f954f3 |
|
|
|
f954f3 |
- if (pwrite (fd, block, blksize, offset) == -1) {
|
|
|
f954f3 |
+ if (full_pwrite (fd, block, blksize, offset) == -1) {
|
|
|
f954f3 |
*err = errno;
|
|
|
f954f3 |
nbdkit_error ("pwrite: %m");
|
|
|
f954f3 |
return -1;
|
|
|
f954f3 |
@@ -414,7 +414,7 @@ blk_write (nbdkit_next *next,
|
|
|
f954f3 |
nbdkit_debug ("cache: writeback block %" PRIu64 " (offset %" PRIu64 ")",
|
|
|
f954f3 |
blknum, (uint64_t) offset);
|
|
|
f954f3 |
|
|
|
f954f3 |
- if (pwrite (fd, block, blksize, offset) == -1) {
|
|
|
f954f3 |
+ if (full_pwrite (fd, block, blksize, offset) == -1) {
|
|
|
f954f3 |
*err = errno;
|
|
|
f954f3 |
nbdkit_error ("pwrite: %m");
|
|
|
f954f3 |
return -1;
|
|
|
f954f3 |
diff --git a/filters/cow/blk.c b/filters/cow/blk.c
|
|
|
f954f3 |
index 4ec8d1b8..121b0dd4 100644
|
|
|
f954f3 |
--- a/filters/cow/blk.c
|
|
|
f954f3 |
+++ b/filters/cow/blk.c
|
|
|
f954f3 |
@@ -278,7 +278,7 @@ blk_read_multiple (nbdkit_next *next,
|
|
|
f954f3 |
memset (block + n, 0, tail);
|
|
|
f954f3 |
}
|
|
|
f954f3 |
else if (state == BLOCK_ALLOCATED) { /* Read overlay. */
|
|
|
f954f3 |
- if (pread (fd, block, BLKSIZE * runblocks, offset) == -1) {
|
|
|
f954f3 |
+ if (full_pread (fd, block, BLKSIZE * runblocks, offset) == -1) {
|
|
|
f954f3 |
*err = errno;
|
|
|
f954f3 |
nbdkit_error ("pread: %m");
|
|
|
f954f3 |
return -1;
|
|
|
f954f3 |
@@ -353,7 +353,7 @@ blk_cache (nbdkit_next *next,
|
|
|
f954f3 |
memset (block + n, 0, tail);
|
|
|
f954f3 |
|
|
|
f954f3 |
if (mode == BLK_CACHE_COW) {
|
|
|
f954f3 |
- if (pwrite (fd, block, BLKSIZE, offset) == -1) {
|
|
|
f954f3 |
+ if (full_pwrite (fd, block, BLKSIZE, offset) == -1) {
|
|
|
f954f3 |
*err = errno;
|
|
|
f954f3 |
nbdkit_error ("pwrite: %m");
|
|
|
f954f3 |
return -1;
|
|
|
f954f3 |
@@ -372,7 +372,7 @@ blk_write (uint64_t blknum, const uint8_t *block, int *err)
|
|
|
f954f3 |
nbdkit_debug ("cow: blk_write block %" PRIu64 " (offset %" PRIu64 ")",
|
|
|
f954f3 |
blknum, (uint64_t) offset);
|
|
|
f954f3 |
|
|
|
f954f3 |
- if (pwrite (fd, block, BLKSIZE, offset) == -1) {
|
|
|
f954f3 |
+ if (full_pwrite (fd, block, BLKSIZE, offset) == -1) {
|
|
|
f954f3 |
*err = errno;
|
|
|
f954f3 |
nbdkit_error ("pwrite: %m");
|
|
|
f954f3 |
return -1;
|
|
|
f954f3 |
--
|
|
|
f954f3 |
2.31.1
|
|
|
f954f3 |
|