Enable allow_discards if dm-crypt supports it

dm-crypt version 1.11.0 and later supports the allow_discards option
when setting up a crypto device.  This passes discard requests from
the filesytem to the underlying block device.  This helps make flash
based storage faster.  So query the dm-crypt version, and pass the
option if the version is 1.11.0 or greater.

Change-Id: If30e9db5a2dbd6ea0281d91344e5b2c35e75131e
This commit is contained in:
Ken Sumrall 2013-02-05 17:39:48 -08:00
parent 2ba45aafc2
commit db5e026058

124
cryptfs.c
View file

@ -377,6 +377,86 @@ void convert_key_to_hex_ascii(unsigned char *master_key, unsigned int keysize,
}
static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
char *real_blk_name, const char *name, int fd,
char *extra_params)
{
char buffer[DM_CRYPT_BUF_SIZE];
struct dm_ioctl *io;
struct dm_target_spec *tgt;
char *crypt_params;
char master_key_ascii[129]; /* Large enough to hold 512 bit key and null */
int i;
io = (struct dm_ioctl *) buffer;
/* Load the mapping table for this device */
tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
io->target_count = 1;
tgt->status = 0;
tgt->sector_start = 0;
tgt->length = crypt_ftr->fs_size;
strcpy(tgt->target_type, "crypt");
crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
sprintf(crypt_params, "%s %s 0 %s 0 %s", crypt_ftr->crypto_type_name,
master_key_ascii, real_blk_name, extra_params);
crypt_params += strlen(crypt_params) + 1;
crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
tgt->next = crypt_params - buffer;
for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
if (! ioctl(fd, DM_TABLE_LOAD, io)) {
break;
}
usleep(500000);
}
if (i == TABLE_LOAD_RETRIES) {
/* We failed to load the table, return an error */
return -1;
} else {
return i + 1;
}
}
static int get_dm_crypt_version(int fd, const char *name, int *version)
{
char buffer[DM_CRYPT_BUF_SIZE];
struct dm_ioctl *io;
struct dm_target_versions *v;
int i;
io = (struct dm_ioctl *) buffer;
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
if (ioctl(fd, DM_LIST_VERSIONS, io)) {
return -1;
}
/* Iterate over the returned versions, looking for name of "crypt".
* When found, get and return the version.
*/
v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)];
while (v->next) {
if (! strcmp(v->name, "crypt")) {
/* We found the crypt driver, return the version, and get out */
version[0] = v->version[0];
version[1] = v->version[1];
version[2] = v->version[2];
return 0;
}
v = (struct dm_target_versions *)(((char *)v) + v->next);
}
return -1;
}
static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
char *real_blk_name, char *crypto_blk_name, const char *name)
{
@ -389,6 +469,9 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char
int fd;
int i;
int retval = -1;
int version[3];
char *extra_params;
int load_count;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) {
SLOGE("Cannot open device-mapper\n");
@ -412,40 +495,27 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char
minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor);
/* Load the mapping table for this device */
tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
ioctl_init(io, 4096, name, 0);
io->target_count = 1;
tgt->status = 0;
tgt->sector_start = 0;
tgt->length = crypt_ftr->fs_size;
strcpy(tgt->target_type, "crypt");
crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
sprintf(crypt_params, "%s %s 0 %s 0", crypt_ftr->crypto_type_name,
master_key_ascii, real_blk_name);
crypt_params += strlen(crypt_params) + 1;
crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
tgt->next = crypt_params - buffer;
for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
if (! ioctl(fd, DM_TABLE_LOAD, io)) {
break;
}
usleep(500000);
extra_params = "";
if (! get_dm_crypt_version(fd, name, version)) {
/* Support for allow_discards was added in version 1.11.0 */
if ((version[0] >= 2) ||
((version[0] == 1) && (version[1] >= 11))) {
extra_params = "1 allow_discards";
SLOGI("Enabling support for allow_discards in dmcrypt.\n");
}
}
if (i == TABLE_LOAD_RETRIES) {
load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name,
fd, extra_params);
if (load_count < 0) {
SLOGE("Cannot load dm-crypt mapping table.\n");
goto errout;
} else if (i) {
SLOGI("Took %d tries to load dmcrypt table.\n", i + 1);
} else if (load_count > 1) {
SLOGI("Took %d tries to load dmcrypt table.\n", load_count);
}
/* Resume this device to activate it */
ioctl_init(io, 4096, name, 0);
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
SLOGE("Cannot resume the dm-crypt device\n");