From f16f37233f87fb2758c9a2181fde4d97b93a418a Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Sat, 4 Oct 2014 15:30:08 +0200 Subject: [PATCH] Fix partial reads and handle EINTR in reencryption code. The partial read usually happens only on IO error, so reencrypt at least part what is read properly. For EINTR code must restart read completely. Fixes issue#226. --- src/cryptsetup_reencrypt.c | 43 +++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/cryptsetup_reencrypt.c b/src/cryptsetup_reencrypt.c index a1cc51d5..f36316a7 100644 --- a/src/cryptsetup_reencrypt.c +++ b/src/cryptsetup_reencrypt.c @@ -652,6 +652,29 @@ static void print_progress(struct reenc_ctx *rc, uint64_t bytes, int final) final ? "\n" :""); } +static ssize_t read_buf(int fd, void *buf, size_t count) +{ + size_t read_size = 0; + ssize_t s; + + do { + /* This expects that partial read is aligned in buffer */ + s = read(fd, buf, count - read_size); + if (s == -1 && errno != EINTR) + return s; + if (s == 0) + return (ssize_t)read_size; + if (s > 0) { + if (s != count) + log_dbg("Partial read %zd / %zu.", s, count); + read_size += (size_t)s; + buf += s; + } + } while (read_size != count); + + return (ssize_t)count; +} + static int copy_data_forward(struct reenc_ctx *rc, int fd_old, int fd_new, size_t block_size, void *buf, uint64_t *bytes) { @@ -671,11 +694,11 @@ static int copy_data_forward(struct reenc_ctx *rc, int fd_old, int fd_new, return -EIO; while (!quit && rc->device_offset < rc->device_size) { - s1 = read(fd_old, buf, block_size); + s1 = read_buf(fd_old, buf, block_size); if (s1 < 0 || ((size_t)s1 != block_size && (rc->device_offset + s1) != rc->device_size)) { - log_dbg("Read error, expecting %d, got %d.", - (int)block_size, (int)s1); + log_dbg("Read error, expecting %zu, got %zd.", + block_size, s1); return -EIO; } @@ -685,8 +708,8 @@ static int copy_data_forward(struct reenc_ctx *rc, int fd_old, int fd_new, s2 = write(fd_new, buf, s1); if (s2 < 0) { - log_dbg("Write error, expecting %d, got %d.", - (int)block_size, (int)s2); + log_dbg("Write error, expecting %zu, got %zd.", + block_size, s2); return -EIO; } @@ -741,17 +764,17 @@ static int copy_data_backward(struct reenc_ctx *rc, int fd_old, int fd_new, return -EIO; } - s1 = read(fd_old, buf, working_block); + s1 = read_buf(fd_old, buf, working_block); if (s1 < 0 || (s1 != working_block)) { - log_dbg("Read error, expecting %d, got %d.", - (int)block_size, (int)s1); + log_dbg("Read error, expecting %zu, got %zd.", + block_size, s1); return -EIO; } s2 = write(fd_new, buf, working_block); if (s2 < 0) { - log_dbg("Write error, expecting %d, got %d.", - (int)block_size, (int)s2); + log_dbg("Write error, expecting %zu, got %zd.", + block_size, s2); return -EIO; }