diff --git a/lib/internal.h b/lib/internal.h index fb265eef..5d776003 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -75,6 +75,8 @@ int device_block_size(struct device *device); int device_read_ahead(struct device *device, uint32_t *read_ahead); int device_size(struct device *device, uint64_t *size); int device_open(struct device *device, int flags); +void device_disable_direct_io(struct device *device); + enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 }; int device_block_adjust(struct crypt_device *cd, diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c index 44673c39..16968fbc 100644 --- a/lib/luks1/keymanage.c +++ b/lib/luks1/keymanage.c @@ -545,6 +545,16 @@ int LUKS_read_phdr(struct luks_phdr *hdr, if (!r) r = LUKS_check_device_size(ctx, hdr->keyBytes); + /* + * Cryptsetup 1.0.0 did not align keyslots to 4k (very rare version). + * Disable direct-io to avoid possible IO errors if underlying device + * has bigger sector size. + */ + if (!r && hdr->keyblock[0].keyMaterialOffset * SECTOR_SIZE < LUKS_ALIGN_KEYSLOTS) { + log_dbg("Old unaligned LUKS keyslot detected, disabling direct-io."); + device_disable_direct_io(device); + } + close(devfd); return r; } diff --git a/lib/utils_device.c b/lib/utils_device.c index 72899338..8c4d4349 100644 --- a/lib/utils_device.c +++ b/lib/utils_device.c @@ -530,3 +530,8 @@ size_t size_round_up(size_t size, unsigned int block) size_t s = (size + (block - 1)) / block; return s * block; } + +void device_disable_direct_io(struct device *device) +{ + device->o_direct = 0; +}