Use common function for accessing FEC devices.

TODO: the device wrappet should hanbdle EINTR better...
This commit is contained in:
Milan Broz
2017-04-05 10:58:03 +02:00
parent 3a058a4f21
commit 1da785cb77
3 changed files with 68 additions and 131 deletions

View File

@@ -1097,7 +1097,7 @@ static int _crypt_format_verity(struct crypt_device *cd,
r = VERITY_create(cd, &cd->u.verity.hdr, r = VERITY_create(cd, &cd->u.verity.hdr,
cd->u.verity.root_hash, cd->u.verity.root_hash_size); cd->u.verity.root_hash, cd->u.verity.root_hash_size);
if (!r && params->fec_device) if (!r && params->fec_device)
r = VERITY_FEC_create(cd, &cd->u.verity.hdr); r = VERITY_FEC_create(cd, &cd->u.verity.hdr, cd->u.verity.fec_device);
if (r) if (r)
return r; return r;
} }

View File

@@ -60,7 +60,8 @@ int VERITY_create(struct crypt_device *cd,
size_t root_hash_size); size_t root_hash_size);
int VERITY_FEC_create(struct crypt_device *cd, int VERITY_FEC_create(struct crypt_device *cd,
struct crypt_params_verity *params); struct crypt_params_verity *params,
struct device *fec_device);
uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params); uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params);
uint64_t VERITY_FEC_offset_block(struct crypt_params_verity *params); uint64_t VERITY_FEC_offset_block(struct crypt_params_verity *params);

View File

@@ -2,6 +2,7 @@
* dm-verity Forward Error Correction (FEC) support * dm-verity Forward Error Correction (FEC) support
* *
* Copyright (C) 2015, Google, Inc. All rights reserved. * Copyright (C) 2015, Google, Inc. All rights reserved.
* Copyright (C) 2017, Red Hat, Inc. All rights reserved.
* *
* This file is free software; you can redistribute it and/or * This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@@ -36,6 +37,8 @@
#define FEC_MIN_RSN 231 #define FEC_MIN_RSN 231
#define FEC_MAX_RSN 253 #define FEC_MAX_RSN 253
#define FEC_INPUT_DEVICES 2
/* parameters to init_rs_char */ /* parameters to init_rs_char */
#define FEC_PARAMS(roots) \ #define FEC_PARAMS(roots) \
8, /* symbol size in bits */ \ 8, /* symbol size in bits */ \
@@ -45,11 +48,6 @@
(roots), /* polynomial degree (number of roots) */ \ (roots), /* polynomial degree (number of roots) */ \
0 /* padding bytes at the front of shortened block */ 0 /* padding bytes at the front of shortened block */
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(array) \
sizeof(array) / sizeof(array[0])
#endif
#define FEC_SIGNATURE "fec...\0\0" #define FEC_SIGNATURE "fec...\0\0"
#define FEC_VERSION 0 #define FEC_VERSION 0
@@ -94,52 +92,12 @@ uint64_t VERITY_FEC_offset_block(struct crypt_params_verity *params)
return fec_offset / params->hash_block_size; return fec_offset / params->hash_block_size;
} }
/* computes ceil(x / y) */ /* computes ceil(x / y) */
static inline uint64_t FEC_div_round_up(uint64_t x, uint64_t y) static inline uint64_t FEC_div_round_up(uint64_t x, uint64_t y)
{ {
return (x / y) + (x % y > 0 ? 1 : 0); return (x / y) + (x % y > 0 ? 1 : 0);
} }
/* writes the entire data buffer to fd */
int FEC_write(int fd, const void *p, size_t count)
{
const uint8_t *data = (const uint8_t *)p;
size_t left = count;
while (left > 0) {
ssize_t n = TEMP_FAILURE_RETRY(write(fd, data, left));
if (n == -1)
return -errno;
data += n;
left -= n;
}
return 0;
}
/* reads count bytes to data from fd at offset */
int FEC_pread(int fd, uint8_t *data, size_t count, uint64_t offset)
{
size_t left = count;
while (left > 0) {
ssize_t n = TEMP_FAILURE_RETRY(pread64(fd, data, left,
offset));
if (n <= 0)
return -errno;
data += n;
left -= n;
offset += n;
}
return 0;
}
/* returns a physical offset for the given RS offset */ /* returns a physical offset for the given RS offset */
static inline uint64_t FEC_interleave(struct fec_context *ctx, uint64_t offset) static inline uint64_t FEC_interleave(struct fec_context *ctx, uint64_t offset)
{ {
@@ -148,8 +106,8 @@ static inline uint64_t FEC_interleave(struct fec_context *ctx, uint64_t offset)
} }
/* returns data for a byte at the specified RS offset */ /* returns data for a byte at the specified RS offset */
int FEC_read_interleaved(struct fec_context *ctx, uint64_t i, uint8_t *output, static int FEC_read_interleaved(struct fec_context *ctx, uint64_t i,
size_t count) void *output, size_t count)
{ {
size_t n; size_t n;
uint64_t offset = FEC_interleave(ctx, i); uint64_t offset = FEC_interleave(ctx, i);
@@ -165,10 +123,11 @@ int FEC_read_interleaved(struct fec_context *ctx, uint64_t i, uint8_t *output,
if (offset >= ctx->inputs[n].count) { if (offset >= ctx->inputs[n].count) {
offset -= ctx->inputs[n].count; offset -= ctx->inputs[n].count;
continue; continue;
} }
return FEC_pread(ctx->inputs[n].fd, output, count, if (lseek(ctx->inputs[n].fd, ctx->inputs[n].start + offset, SEEK_SET) < 0)
ctx->inputs[n].start + offset); return -1;
return (read_buffer(ctx->inputs[n].fd, output, count) == count) ? 0 : -1;
} }
/* should never be reached */ /* should never be reached */
@@ -181,11 +140,11 @@ static int FEC_write_sb(struct fec_context *ctx, int fd)
memset(&sb, 0, sizeof(sb)); memset(&sb, 0, sizeof(sb));
memcpy(&sb.signature, FEC_SIGNATURE, sizeof(sb.signature)); memcpy(&sb.signature, FEC_SIGNATURE, sizeof(sb.signature));
sb.version = FEC_VERSION; sb.version = FEC_VERSION; // FIXME: endianess
sb.roots = ctx->roots; sb.roots = ctx->roots; // FIXME: endianess
sb.blocks = ctx->size / ctx->block_size; sb.blocks = ctx->size / ctx->block_size; // FIXME: endianess
return FEC_write(fd, &sb, sizeof(sb)); return (write_buffer(fd, &sb, sizeof(sb)) == sizeof(sb)) ? 0 : -1;
} }
/* encodes inputs to fd */ /* encodes inputs to fd */
@@ -234,25 +193,19 @@ static int FEC_encode_inputs(struct crypt_device *cd,
} }
/* write superblock */ /* write superblock */
if (!(params->flags & CRYPT_VERITY_NO_HEADER)) { if (!(params->flags & CRYPT_VERITY_NO_HEADER) && FEC_write_sb(&ctx, fd)) {
r = FEC_write_sb(&ctx, fd); log_err(cd, _("Failed to write FEC superblock.\n"));
if (r) { r = -EIO;
log_err(cd, _("Failed to write FEC superblock.\n")); goto out;
goto out;
}
} }
/* encode input */ /* encode input */
for (n = 0; n < ctx.rounds; ++n) { for (n = 0; n < ctx.rounds; ++n) {
for (i = 0; i < ctx.rsn; ++i) { for (i = 0; i < ctx.rsn; ++i) {
r = FEC_read_interleaved(&ctx, if (FEC_read_interleaved(&ctx, n * ctx.rsn * ctx.block_size + i,
n * ctx.rsn * ctx.block_size + i, &buf[i * ctx.block_size], ctx.block_size)) {
&buf[i * ctx.block_size], log_err(cd, _("Failed to read RS block %" PRIu64 " byte %d.\n"), n, i);
ctx.block_size); r = -EIO;
if (r) {
log_err(cd, _("Failed to read RS block %"
PRIu64 " byte %d.\n"), n, i);
goto out; goto out;
} }
} }
@@ -262,11 +215,9 @@ static int FEC_encode_inputs(struct crypt_device *cd,
rs_block[i] = buf[i * ctx.block_size + b]; rs_block[i] = buf[i * ctx.block_size + b];
encode_rs_char(rs, rs_block, parity); encode_rs_char(rs, rs_block, parity);
r = FEC_write(fd, parity, sizeof(parity)); if (write_buffer(fd, parity, sizeof(parity)) != sizeof(parity)) {
log_err(cd, _("Failed to write parity for RS block %" PRIu64 ".\n"), n);
if (r) { r = -EIO;
log_err(cd, _("Failed to write parity for RS "
"block %" PRIu64 ".\n"), n);
goto out; goto out;
} }
} }
@@ -277,39 +228,27 @@ out:
free_rs_char(rs); free_rs_char(rs);
free(buf); free(buf);
return r; return r;
} }
static int FEC_open_inputs(struct crypt_device *cd,
struct fec_input_device *inputs,
size_t ninputs)
{
size_t n;
for (n = 0; n < ninputs; ++n)
inputs[n].fd = -1;
for (n = 0; n < ninputs; ++n) {
inputs[n].fd =
TEMP_FAILURE_RETRY(open(device_path(inputs[n].device),
O_RDWR));
if (inputs[n].fd == -1) {
log_err(cd, _("Failed to open %s.\n"),
device_path(inputs[n].device));
return -errno;
}
}
return 0;
}
int VERITY_FEC_create(struct crypt_device *cd, int VERITY_FEC_create(struct crypt_device *cd,
struct crypt_params_verity *params) struct crypt_params_verity *params,
struct device *fec_device)
{ {
int r; int r;
int fd = -1; int fd = -1;
struct fec_input_device inputs[2]; struct fec_input_device inputs[FEC_INPUT_DEVICES] = {
{
.device = crypt_data_device(cd),
.fd = -1,
.start = 0,
.count = params->data_size * params->data_block_size
},{
.device = crypt_metadata_device(cd),
.fd = -1,
.start = VERITY_hash_offset_block(params) * params->data_block_size
}
};
/* validate parameters */ /* validate parameters */
if (params->data_block_size != params->hash_block_size) { if (params->data_block_size != params->hash_block_size) {
@@ -323,52 +262,49 @@ int VERITY_FEC_create(struct crypt_device *cd,
return -EINVAL; return -EINVAL;
} }
/* open the output device */ r = -EIO;
fd = TEMP_FAILURE_RETRY(open(params->fec_device, O_RDWR | O_CLOEXEC));
/* output device */
fd = open(device_path(fec_device), O_RDWR);
if (fd == -1) { if (fd == -1) {
log_err(cd, _("Cannot open device %s.\n"), params->fec_device); log_err(cd, _("Cannot open device %s.\n"), device_path(fec_device));
return -errno; goto out;
} }
if (lseek(fd, params->fec_area_offset, SEEK_SET) != params->fec_area_offset) { if (lseek(fd, params->fec_area_offset, SEEK_SET) < 0) {
log_dbg("Cannot seek to requested position in FEC device."); log_dbg("Cannot seek to requested position in FEC device.");
TEMP_FAILURE_RETRY(close(fd)); goto out;
return -EIO;
} }
/* input devices */ /* input devices */
memset(inputs, 0, sizeof(inputs)); inputs[0].fd = open(device_path(inputs[0].device), O_RDONLY);
if (inputs[0].fd == -1) {
inputs[0].device = crypt_data_device(cd); log_err(cd, _("Cannot open device %s.\n"), device_path(inputs[0].device));
inputs[0].count = params->data_size * params->data_block_size; goto out;
}
/* cover the entire hash device starting from hash_offset */ inputs[1].fd = open(device_path(inputs[1].device), O_RDONLY);
inputs[1].device = crypt_metadata_device(cd); if (inputs[1].fd == -1) {
inputs[1].start = VERITY_hash_offset_block(params) * log_err(cd, _("Cannot open device %s.\n"), device_path(inputs[1].device));
params->data_block_size;
r = device_size(crypt_metadata_device(cd), &inputs[1].count);
if (r) {
log_err(cd, _("Failed to determine size for device %s.\n"),
device_path(crypt_metadata_device(cd)));
goto out; goto out;
} }
/* cover the entire hash device starting from hash_offset */
r = device_size(inputs[1].device, &inputs[1].count);
if (r) {
log_err(cd, _("Failed to determine size for device %s.\n"),
device_path(inputs[1].device));
goto out;
}
inputs[1].count -= inputs[1].start; inputs[1].count -= inputs[1].start;
r = FEC_open_inputs(cd, inputs, ARRAY_SIZE(inputs)); r = FEC_encode_inputs(cd, params, inputs, FEC_INPUT_DEVICES, fd);
if (r)
goto out;
r = FEC_encode_inputs(cd, params, inputs, ARRAY_SIZE(inputs), fd);
out: out:
if (inputs[0].fd != -1) if (inputs[0].fd != -1)
TEMP_FAILURE_RETRY(close(inputs[0].fd)); close(inputs[0].fd);
if (inputs[1].fd != -1) if (inputs[1].fd != -1)
TEMP_FAILURE_RETRY(close(inputs[1].fd)); close(inputs[1].fd);
if (fd != -1) if (fd != -1)
TEMP_FAILURE_RETRY(close(fd)); close(fd);
return r; return r;
} }