Commit 34bf809e authored by Milan Broz's avatar Milan Broz

Use device alignment wrapper.

And cache the value to not call ioctl on every block read/write.
parent fd6fc160
......@@ -40,7 +40,7 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
}
if (read_lseek_blockwise(devfd, device_block_size(device),
sb, sizeof(*sb), offset) != sizeof(*sb) ||
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
sb->version != SB_VERSION) {
log_std(cd, "No integrity superblock detected on %s.\n",
......
......@@ -79,6 +79,7 @@ int device_open(struct device *device, int flags);
void device_disable_direct_io(struct device *device);
int device_is_identical(struct device *device1, struct device *device2);
int device_is_rotational(struct device *device);
size_t device_alignment(struct device *device);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
int device_block_adjust(struct crypt_device *cd,
......@@ -104,10 +105,10 @@ uint64_t crypt_dev_partition_offset(const char *dev_path);
ssize_t write_buffer(int fd, const void *buf, size_t count);
ssize_t read_buffer(int fd, void *buf, size_t count);
ssize_t write_blockwise(int fd, int bsize, void *buf, size_t count);
ssize_t read_blockwise(int fd, int bsize, void *buf, size_t count);
ssize_t write_lseek_blockwise(int fd, int bsize, void *buf, size_t count, off_t offset);
ssize_t read_lseek_blockwise(int fd, int bsize, void *buf, size_t count, off_t offset);
ssize_t write_blockwise(int fd, int bsize, size_t alignment, void *orig_buf, size_t count);
ssize_t read_blockwise(int fd, int bsize, size_t alignment, void *buf, size_t count);
ssize_t write_lseek_blockwise(int fd, int bsize, size_t alignment, void *buf, size_t count, off_t offset);
ssize_t read_lseek_blockwise(int fd, int bsize, size_t alignment, void *buf, size_t count, off_t offset);
unsigned crypt_getpagesize(void);
int init_crypto(struct crypt_device *ctx);
......
......@@ -46,7 +46,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
const char *cipher, const char *cipher_mode,
struct volume_key *vk,
unsigned int sector,
ssize_t (*func)(int, int, void *, size_t),
ssize_t (*func)(int, int, size_t, void *, size_t),
int mode,
struct crypt_device *ctx)
{
......@@ -65,11 +65,13 @@ static int LUKS_endec_template(char *src, size_t srcLength,
}
};
int r, bsize, devfd = -1;
size_t alignment;
log_dbg("Using dmcrypt to access keyslot area.");
bsize = device_block_size(dmd.data_device);
if (bsize <= 0)
alignment = device_alignment(dmd.data_device);
if (bsize <= 0 || !alignment)
return -EINVAL;
dmd.size = size_round_up(srcLength, bsize) / SECTOR_SIZE;
......@@ -113,7 +115,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
goto out;
}
r = func(devfd, bsize, src, srcLength);
r = func(devfd, bsize, alignment, src, srcLength);
if (r < 0) {
log_err(ctx, _("Failed to access temporary keystore device.\n"));
r = -EIO;
......@@ -137,6 +139,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
struct device *device = crypt_metadata_device(ctx);
struct crypt_storage *s;
int devfd = -1, bsize, r = 0;
size_t alignment;
/* Only whole sector writes supported */
if (srcLength % SECTOR_SIZE)
......@@ -172,7 +175,8 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
/* Write buffer to device */
bsize = device_block_size(device);
if (bsize <= 0)
alignment = device_alignment(device);
if (bsize <= 0 || !alignment)
goto out;
devfd = device_open(device, O_RDWR);
......@@ -180,7 +184,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
goto out;
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
write_blockwise(devfd, bsize, src, srcLength) == -1)
write_blockwise(devfd, bsize, alignment, src, srcLength) == -1)
goto out;
r = 0;
......@@ -203,6 +207,7 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
struct device *device = crypt_metadata_device(ctx);
struct crypt_storage *s;
int devfd = -1, bsize, r = 0;
size_t alignment;
/* Only whole sector reads supported */
if (dstLength % SECTOR_SIZE)
......@@ -231,7 +236,8 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
/* Read buffer from device */
bsize = device_block_size(device);
if (bsize <= 0)
alignment = device_alignment(device);
if (bsize <= 0 || !alignment)
goto bad;
devfd = device_open(device, O_RDONLY);
......@@ -239,7 +245,7 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
goto bad;
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
read_blockwise(devfd, bsize, dst, dstLength) == -1)
read_blockwise(devfd, bsize, alignment, dst, dstLength) == -1)
goto bad;
close(devfd);
......
......@@ -182,7 +182,8 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
goto out;
}
if (read_blockwise(devfd, device_block_size(device), buffer, hdr_size) < hdr_size) {
if (read_blockwise(devfd, device_block_size(device), device_alignment(device),
buffer, hdr_size) < hdr_size) {
r = -EIO;
goto out;
}
......@@ -301,7 +302,8 @@ int LUKS_hdr_restore(
goto out;
}
if (write_blockwise(devfd, device_block_size(device), buffer, buffer_size) < buffer_size) {
if (write_blockwise(devfd, device_block_size(device), device_alignment(device),
buffer, buffer_size) < buffer_size) {
r = -EIO;
goto out;
}
......@@ -537,7 +539,8 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
return -EINVAL;
}
if (read_blockwise(devfd, device_block_size(device), hdr, hdr_size) < hdr_size)
if (read_blockwise(devfd, device_block_size(device), device_alignment(device),
hdr, hdr_size) < hdr_size)
r = -EIO;
else
r = _check_and_convert_hdr(device_path(device), hdr, require_luks_device,
......@@ -602,7 +605,8 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
convHdr.keyblock[i].stripes = htonl(hdr->keyblock[i].stripes);
}
r = write_blockwise(devfd, device_block_size(device), &convHdr, hdr_size) < hdr_size ? -EIO : 0;
r = write_blockwise(devfd, device_block_size(device), device_alignment(device),
&convHdr, hdr_size) < hdr_size ? -EIO : 0;
if (r)
log_err(ctx, _("Error during update of LUKS header on device %s.\n"), device_path(device));
close(devfd);
......
......@@ -601,6 +601,7 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
ssize_t hdr_size = sizeof(struct tcrypt_phdr);
char *base_device_path;
int devfd = 0, r, bs;
size_t alignment;
assert(sizeof(struct tcrypt_phdr) == 512);
......@@ -608,6 +609,7 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
hdr_size, device_path(device));
bs = device_block_size(device);
alignment = device_alignment(device);
if (bs < 0)
return bs;
......@@ -635,28 +637,28 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
r = -EIO;
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) {
if (read_lseek_blockwise(devfd, bs, hdr, hdr_size,
if (read_lseek_blockwise(devfd, bs, alignment, hdr, hdr_size,
TCRYPT_HDR_SYSTEM_OFFSET) == hdr_size) {
r = TCRYPT_init_hdr(cd, hdr, params);
}
} else if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) {
if (params->flags & CRYPT_TCRYPT_BACKUP_HEADER) {
if (read_lseek_blockwise(devfd, bs, hdr, hdr_size,
if (read_lseek_blockwise(devfd, bs, alignment, hdr, hdr_size,
TCRYPT_HDR_HIDDEN_OFFSET_BCK) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
} else {
if (read_lseek_blockwise(devfd, bs, hdr, hdr_size,
if (read_lseek_blockwise(devfd, bs, alignment, hdr, hdr_size,
TCRYPT_HDR_HIDDEN_OFFSET) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
if (r && read_lseek_blockwise(devfd, bs, hdr, hdr_size,
if (r && read_lseek_blockwise(devfd, bs, alignment, hdr, hdr_size,
TCRYPT_HDR_HIDDEN_OFFSET_OLD) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
}
} else if (params->flags & CRYPT_TCRYPT_BACKUP_HEADER) {
if (read_lseek_blockwise(devfd, bs, hdr, hdr_size,
if (read_lseek_blockwise(devfd, bs, alignment, hdr, hdr_size,
TCRYPT_HDR_OFFSET_BCK) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
} else if (read_blockwise(devfd, bs, hdr, hdr_size) == hdr_size)
} else if (read_blockwise(devfd, bs, alignment, hdr, hdr_size) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
close(devfd);
......
......@@ -36,18 +36,6 @@ unsigned crypt_getpagesize(void)
return r < 0 ? DEFAULT_MEM_ALIGNMENT : r;
}
static size_t get_alignment(int fd)
{
long alignment = DEFAULT_MEM_ALIGNMENT;
#ifdef _PC_REC_XFER_ALIGN
alignment = fpathconf(fd, _PC_REC_XFER_ALIGN);
if (alignment < 0)
alignment = DEFAULT_MEM_ALIGNMENT;
#endif
return (size_t)alignment;
}
ssize_t read_buffer(int fd, void *buf, size_t count)
{
size_t read_size = 0;
......@@ -94,19 +82,18 @@ ssize_t write_buffer(int fd, const void *buf, size_t count)
return (ssize_t)write_size;
}
ssize_t write_blockwise(int fd, int bsize, void *orig_buf, size_t count)
ssize_t write_blockwise(int fd, int bsize, size_t alignment, void *orig_buf, size_t count)
{
void *hangover_buf = NULL, *buf = NULL;
int r;
size_t alignment, hangover, solid;
size_t hangover, solid;
ssize_t ret = -1;
if (fd == -1 || !orig_buf || bsize <= 0)
if (fd == -1 || !orig_buf || bsize <= 0 || !alignment)
return -1;
hangover = count % bsize;
solid = count - hangover;
alignment = get_alignment(fd);
if ((size_t)orig_buf & (alignment - 1)) {
if (posix_memalign(&buf, alignment, count))
......@@ -149,19 +136,18 @@ out:
return ret;
}
ssize_t read_blockwise(int fd, int bsize, void *orig_buf, size_t count)
ssize_t read_blockwise(int fd, int bsize, size_t alignment, void *orig_buf, size_t count)
{
void *hangover_buf = NULL, *buf = NULL;
int r;
size_t alignment, hangover, solid;
size_t hangover, solid;
ssize_t ret = -1;
if (fd == -1 || !orig_buf || bsize <= 0)
if (fd == -1 || !orig_buf || bsize <= 0 || !alignment)
return -1;
hangover = count % bsize;
solid = count - hangover;
alignment = get_alignment(fd);
if ((size_t)orig_buf & (alignment - 1)) {
if (posix_memalign(&buf, alignment, count))
......@@ -198,7 +184,7 @@ out:
* is implicitly included in the read/write offset, which can not be set to non-aligned
* boundaries. Hence, we combine llseek with write.
*/
ssize_t write_lseek_blockwise(int fd, int bsize, void *buf, size_t count, off_t offset)
ssize_t write_lseek_blockwise(int fd, int bsize, size_t alignment, void *buf, size_t count, off_t offset)
{
void *frontPadBuf = NULL;
int r, frontHang;
......@@ -220,7 +206,7 @@ ssize_t write_lseek_blockwise(int fd, int bsize, void *buf, size_t count, off_t
return -1;
if (frontHang) {
if (posix_memalign(&frontPadBuf, get_alignment(fd), bsize))
if (posix_memalign(&frontPadBuf, alignment, bsize))
return -1;
r = read_buffer(fd, frontPadBuf, bsize);
......@@ -244,7 +230,7 @@ ssize_t write_lseek_blockwise(int fd, int bsize, void *buf, size_t count, off_t
count -= innerCount;
}
ret = count ? write_blockwise(fd, bsize, buf, count) : 0;
ret = count ? write_blockwise(fd, bsize, alignment, buf, count) : 0;
if (ret >= 0)
ret += innerCount;
out:
......@@ -252,7 +238,7 @@ out:
return ret;
}
ssize_t read_lseek_blockwise(int fd, int bsize, void *buf, size_t count, off_t offset)
ssize_t read_lseek_blockwise(int fd, int bsize, size_t alignment, void *buf, size_t count, off_t offset)
{
void *frontPadBuf = NULL;
int r, frontHang;
......@@ -274,7 +260,7 @@ ssize_t read_lseek_blockwise(int fd, int bsize, void *buf, size_t count, off_t o
return -1;
if (frontHang) {
if (posix_memalign(&frontPadBuf, get_alignment(fd), bsize))
if (posix_memalign(&frontPadBuf, alignment, bsize))
return -1;
r = read_buffer(fd, frontPadBuf, bsize);
......@@ -291,7 +277,7 @@ ssize_t read_lseek_blockwise(int fd, int bsize, void *buf, size_t count, off_t o
count -= innerCount;
}
ret = read_blockwise(fd, bsize, buf, count);
ret = read_blockwise(fd, bsize, alignment, buf, count);
if (ret >= 0)
ret += innerCount;
out:
......
......@@ -43,6 +43,9 @@ struct device {
int o_direct:1;
int init_done:1;
/* cached values */
size_t alignment;
};
static int device_block_size_fd(int fd, size_t *min_size)
......@@ -79,15 +82,28 @@ static int device_block_size_fd(int fd, size_t *min_size)
return bsize;
}
static size_t device_alignment_fd(int devfd)
{
long alignment = DEFAULT_MEM_ALIGNMENT;
#ifdef _PC_REC_XFER_ALIGN
alignment = fpathconf(devfd, _PC_REC_XFER_ALIGN);
if (alignment < 0)
alignment = DEFAULT_MEM_ALIGNMENT;
#endif
return (size_t)alignment;
}
static int device_read_test(int devfd)
{
char buffer[512];
int blocksize, r = -EIO;
size_t minsize = 0;
size_t minsize = 0, alignment;
blocksize = device_block_size_fd(devfd, &minsize);
alignment = device_alignment_fd(devfd);
if (blocksize < 0)
if (blocksize <= 0 || !alignment)
return -EINVAL;
if (minsize == 0)
......@@ -96,7 +112,7 @@ static int device_read_test(int devfd)
if (minsize > sizeof(buffer))
minsize = sizeof(buffer);
if (read_blockwise(devfd, blocksize, buffer, minsize) == (ssize_t)minsize)
if (read_blockwise(devfd, blocksize, alignment, buffer, minsize) == (ssize_t)minsize)
r = 0;
crypt_memzero(buffer, sizeof(buffer));
......@@ -148,6 +164,8 @@ static int device_ready(struct device *device, int check_directio)
else if (!S_ISBLK(st.st_mode))
r = S_ISREG(st.st_mode) ? -ENOTBLK : -EINVAL;
device->alignment = device_alignment_fd(devfd);
close(devfd);
return r;
}
......@@ -566,3 +584,18 @@ int device_is_rotational(struct device *device)
return crypt_dev_is_rotational(major(st.st_rdev), minor(st.st_rdev));
}
size_t device_alignment(struct device *device)
{
int devfd;
if (!device->alignment) {
devfd = open(device_path(device), O_RDONLY);
if (devfd != -1) {
device->alignment = device_alignment_fd(devfd);
close(devfd);
}
}
return device->alignment;
}
......@@ -52,7 +52,7 @@ static void wipeSpecial(char *buffer, size_t buffer_size, unsigned int turn)
}
}
static int crypt_wipe_special(int fd, int bsize, char *buffer,
static int crypt_wipe_special(int fd, int bsize, size_t alignment, char *buffer,
uint64_t offset, size_t size)
{
int r;
......@@ -74,7 +74,8 @@ static int crypt_wipe_special(int fd, int bsize, char *buffer,
if (r < 0)
return r;
written = write_lseek_blockwise(fd, bsize, buffer, size, offset);
written = write_lseek_blockwise(fd, bsize, alignment,
buffer, size, offset);
if (written < 0 || written != (ssize_t)size)
return -EIO;
}
......@@ -83,7 +84,7 @@ static int crypt_wipe_special(int fd, int bsize, char *buffer,
if (crypt_random_get(NULL, buffer, size, CRYPT_RND_NORMAL) < 0)
return -EINVAL;
written = write_lseek_blockwise(fd, bsize, buffer, size, offset);
written = write_lseek_blockwise(fd, bsize, alignment, buffer, size, offset);
if (written < 0 || written != (ssize_t)size)
return -EIO;
......@@ -91,13 +92,14 @@ static int crypt_wipe_special(int fd, int bsize, char *buffer,
}
static int wipe_block(int devfd, crypt_wipe_pattern pattern, char *sf,
size_t device_block_size, size_t wipe_block_size,
uint64_t offset, bool *need_block_init)
size_t device_block_size, size_t alignment,
size_t wipe_block_size, uint64_t offset, bool *need_block_init)
{
int r;
if (pattern == CRYPT_WIPE_SPECIAL)
return crypt_wipe_special(devfd, device_block_size, sf, offset, wipe_block_size);
return crypt_wipe_special(devfd, device_block_size, alignment,
sf, offset, wipe_block_size);
if (*need_block_init) {
if (pattern == CRYPT_WIPE_ZERO) {
......@@ -118,7 +120,8 @@ static int wipe_block(int devfd, crypt_wipe_pattern pattern, char *sf,
return r;
}
if (write_blockwise(devfd, device_block_size, sf, wipe_block_size) == (ssize_t)wipe_block_size)
if (write_blockwise(devfd, device_block_size, alignment, sf,
wipe_block_size) == (ssize_t)wipe_block_size)
return 0;
return -EIO;
......@@ -134,13 +137,15 @@ int crypt_wipe_device(struct crypt_device *cd,
void *usrptr)
{
int r, devfd = -1, bsize;
size_t alignment;
char *sf = NULL;
uint64_t dev_size;
bool need_block_init = true;
/* Note: LUKS1 calls it with wipe_block not aligned to multiple of bsize */
bsize = device_block_size(device);
if ((bsize <= 0) || (wipe_block_size < (size_t)bsize))
alignment = device_alignment(device);
if ((bsize <= 0) || !alignment || (wipe_block_size < (size_t)bsize))
return -EINVAL;
/* Everything must be aligned to SECTOR_SIZE */
......@@ -163,7 +168,7 @@ int crypt_wipe_device(struct crypt_device *cd,
dev_size = offset + length;
}
r = posix_memalign((void **)&sf, crypt_getpagesize(), wipe_block_size);
r = posix_memalign((void **)&sf, alignment, wipe_block_size);
if (r)
goto out;
......@@ -189,7 +194,8 @@ int crypt_wipe_device(struct crypt_device *cd,
//log_dbg("Wipe %012" PRIu64 "-%012" PRIu64 " bytes", offset, offset + wipe_block_size);
r = wipe_block(devfd, pattern, sf, bsize, wipe_block_size, offset, &need_block_init);
r = wipe_block(devfd, pattern, sf, bsize, alignment,
wipe_block_size, offset, &need_block_init);
if (r) {
log_err(cd, "Device wipe error, offset %" PRIu64 ".\n", offset);
break;
......
......@@ -58,7 +58,6 @@ int VERITY_read_sb(struct crypt_device *cd,
struct crypt_params_verity *params)
{
struct device *device = crypt_metadata_device(cd);
int bsize = device_block_size(device);
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
int devfd = 0, sb_version;
......@@ -84,7 +83,8 @@ int VERITY_read_sb(struct crypt_device *cd,
}
if (lseek(devfd, sb_offset, SEEK_SET) < 0 ||
read_blockwise(devfd, bsize, &sb, hdr_size) < hdr_size) {
read_blockwise(devfd, device_block_size(device), device_alignment(device),
&sb, hdr_size) < hdr_size) {
close(devfd);
return -EIO;
}
......@@ -156,7 +156,6 @@ int VERITY_write_sb(struct crypt_device *cd,
struct crypt_params_verity *params)
{
struct device *device = crypt_metadata_device(cd);
int bsize = device_block_size(device);
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
char *algorithm;
......@@ -197,7 +196,8 @@ int VERITY_write_sb(struct crypt_device *cd,
memcpy(sb.salt, params->salt, params->salt_size);
memcpy(sb.uuid, uuid, sizeof(sb.uuid));
r = write_lseek_blockwise(devfd, bsize, (char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0;
r = write_lseek_blockwise(devfd, device_block_size(device), device_alignment(device),
(char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0;
if (r)
log_err(cd, _("Error during update of verity header on device %s.\n"),
device_path(device));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment