Commit 9c71c74d authored by Milan Broz's avatar Milan Broz

Add --enable-discards option to allow discards/TRIM requests.

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@572 36d66b0a-2a48-0410-832c-cd162a569da5
parent 39e6cfcb
2011-07-07 Milan Broz <mbroz@redhat.com>
* Remove old API functions (all functions using crypt_options).
* Add --enable-discards option to allow discards/TRIM requests.
2011-07-01 Milan Broz <mbroz@redhat.com>
* Add --shared option for creating non-overlapping crypt segments.
......
Version 1.4.0:
- Remove old API (all calls using crypt_options)
- Support separation of metadata device
- Wipe device flag
- Support K/M suffixes for align payload (new switch?).
......@@ -377,6 +377,7 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
#define CRYPT_ACTIVATE_READONLY (1 << 0)
#define CRYPT_ACTIVATE_NO_UUID (1 << 1) /* ignored */
#define CRYPT_ACTIVATE_SHARED (1 << 2)
#define CRYPT_ACTIVATE_ALLOW_DISCARDS (1 << 3) /* enable discards aka TRIM */
/**
* Active device runtime attributes
......
......@@ -119,6 +119,9 @@ static void _dm_set_crypt_compat(const char *dm_version, unsigned crypt_maj,
if (crypt_maj >= 1 && crypt_min >= 8)
_dm_crypt_flags |= DM_PLAIN64_SUPPORTED;
if (crypt_maj >= 1 && crypt_min >= 11)
_dm_crypt_flags |= DM_DISCARDS_SUPPORTED;
/* Repeat test if dm-crypt is not present */
if (crypt_maj > 0)
_dm_crypt_checked = 1;
......@@ -238,25 +241,38 @@ static void hex_key(char *hexkey, size_t key_size, const char *key)
sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
}
static char *get_params(const char *device, uint64_t skip, uint64_t offset,
const char *cipher, struct volume_key *vk)
static char *get_params(struct crypt_dm_active_device *dmd)
{
char *params;
char *hexkey;
int r, max_size;
char *params, *hexkey, *features = "";
hexkey = crypt_safe_alloc(vk->keylength * 2 + 1);
if (dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) {
if (dm_flags() & DM_DISCARDS_SUPPORTED) {
features =" 1 allow_discards";
log_dbg("Discard/TRIM is allowed.");
} else
log_dbg("Discard/TRIM is not supported by the kernel.");
}
hexkey = crypt_safe_alloc(dmd->vk->keylength * 2 + 1);
if (!hexkey)
return NULL;
hex_key(hexkey, vk->keylength, vk->key);
hex_key(hexkey, dmd->vk->keylength, dmd->vk->key);
params = crypt_safe_alloc(strlen(hexkey) + strlen(cipher) + strlen(device) + 64);
max_size = strlen(hexkey) + strlen(dmd->cipher) +
strlen(dmd->device) + strlen(features) + 64;
params = crypt_safe_alloc(max_size);
if (!params)
goto out;
sprintf(params, "%s %s %" PRIu64 " %s %" PRIu64,
cipher, hexkey, skip, device, offset);
r = snprintf(params, max_size, "%s %s %" PRIu64 " %s %" PRIu64 "%s",
dmd->cipher, hexkey, dmd->iv_offset, dmd->device,
dmd->offset, features);
if (r < 0 || r >= max_size) {
crypt_safe_free(params);
params = NULL;
}
out:
crypt_safe_free(hexkey);
return params;
......@@ -410,8 +426,7 @@ int dm_create_device(const char *name,
uint32_t cookie = 0;
uint16_t udev_flags = 0;
params = get_params(dmd->device, dmd->iv_offset, dmd->offset,
dmd->cipher, dmd->vk);
params = get_params(dmd);
if (!params)
goto out_no_removal;
......@@ -575,7 +590,7 @@ int dm_query_device(const char *name, uint32_t get_flags,
struct dm_task *dmt;
struct dm_info dmi;
uint64_t start, length, val64;
char *target_type, *params, *rcipher, *key_, *rdevice, *endp, buffer[3];
char *target_type, *params, *rcipher, *key_, *rdevice, *endp, buffer[3], *arg;
const char *tmp_uuid;
void *next = NULL;
unsigned int i;
......@@ -637,10 +652,35 @@ int dm_query_device(const char *name, uint32_t get_flags,
if (!params)
goto out;
val64 = strtoull(params, &params, 10);
if (*params)
goto out;
dmd->offset = val64;
/* Features section, available since crypt target version 1.11 */
if (*params) {
if (*params != ' ')
goto out;
params++;
/* Number of arguments */
val64 = strtoull(params, &params, 10);
if (*params != ' ')
goto out;
params++;
for (i = 0; i < val64; i++) {
if (!params)
goto out;
arg = strsep(&params, " ");
if (!strcasecmp(arg, "allow_discards"))
dmd->flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
else /* unknown option */
goto out;
}
/* All parameters shold be processed */
if (params)
goto out;
}
if (get_flags & DM_ACTIVE_KEY) {
dmd->vk = crypt_alloc_volume_key(strlen(key_) / 2, NULL);
if (!dmd->vk) {
......
......@@ -12,6 +12,7 @@ struct volume_key;
#define DM_LMK_SUPPORTED (1 << 1) /* lmk mode */
#define DM_SECURE_SUPPORTED (1 << 2) /* wipe (secure) buffer flag */
#define DM_PLAIN64_SUPPORTED (1 << 3) /* plain64 IV */
#define DM_DISCARDS_SUPPORTED (1 << 4) /* discards/TRIM option is supported */
uint32_t dm_flags(void);
#define DM_ACTIVE_DEVICE (1 << 0)
......
......@@ -14,7 +14,8 @@ For basic (plain) dm-crypt mappings, there are four operations.
creates a mapping with <name> backed by device <device>.
\fB<options>\fR can be [\-\-hash, \-\-cipher, \-\-verify-passphrase,
\-\-key-file, \-\-key-size, \-\-offset, \-\-skip, \-\-size, \-\-readonly, \-\-shared]
\-\-key-file, \-\-key-size, \-\-offset, \-\-skip, \-\-size, \-\-readonly, \-\-shared,
\-\-allow-discards]
.PP
\fIremove\fR <name>
.IP
......@@ -51,7 +52,7 @@ opens the LUKS partition <device> and sets up a mapping <name> after
successful verification of the supplied key material
(either via key file by \-\-key-file, or via prompting).
\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size, \-\-readonly].
\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size, \-\-readonly, \-\-allow-discards].
.PP
\fIluksClose\fR <name>
.IP
......@@ -186,8 +187,8 @@ and not used it in IV sector calculations, you have to explicitly use
Use \fB\-\-hash\fR to override hash function for password hashing
(otherwise it is detected according to key size).
\fB<options>\fR can be [\-\-key-file, \-\-key-size, \-\-offset, \-\-skip,
\-\-hash, \-\-readonly].
\fB<options>\fR can be [\-\-key-file, \-\-key-size, \-\-offset, \-\-skip,
\-\-hash, \-\-readonly, \-\-allow-discards].
.PP
\fIloopaesClose\fR <name>
.IP
......@@ -361,6 +362,18 @@ new one or change existing UUID in \fIluksUUID\fR command.
The UUID must be provided in standard UUID format
(e.g. 12345678-1234-1234-1234-123456789abc).
.TP
.B "\-\-allow-discards\fR"
Allow using of discards (TRIM) requests for device.
This option is only relevant for \fIcreate\fR, \fIluksOpen\fR or \fIloopaesOpen\fR.
\fBWARNING:\fR Assess the specific security risks carefully before enabling this
option. For example, allowing discards on encrypted devices may lead to the leak
of information about the ciphertext device (filesystem type, used space etc.)
if the discarded blocks can be located easily on the device later.
Kernel version 3.1 or more recent is required.
For older versions is the option ignored.
.TP
.B "\-\-version"
Show the version.
.SH RETURN CODES
......
......@@ -62,6 +62,7 @@ static int opt_random = 0;
static int opt_urandom = 0;
static int opt_dump_master_key = 0;
static int opt_shared = 0;
static int opt_allow_discards = 0;
static const char **action_argv;
static int action_argc;
......@@ -271,6 +272,9 @@ static int action_create(int arg __attribute__((unused)))
if (opt_shared)
activate_flags |= CRYPT_ACTIVATE_SHARED;
if (opt_allow_discards)
activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
if (opt_key_file)
/* With hashing, read the whole keyfile */
r = crypt_activate_by_keyfile(cd, action_argv[0],
......@@ -304,6 +308,7 @@ static int action_loopaesOpen(int arg __attribute__((unused)))
.skip = opt_skip_valid ? opt_skip : opt_offset,
};
unsigned int key_size = (opt_key_size ?: DEFAULT_LOOPAES_KEYBITS) / 8;
uint32_t activate_flags = 0;
int r;
if (!opt_key_file) {
......@@ -311,6 +316,12 @@ static int action_loopaesOpen(int arg __attribute__((unused)))
return -EINVAL;
}
if (opt_readonly)
activate_flags |= CRYPT_ACTIVATE_READONLY;
if (opt_allow_discards)
activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
if ((r = crypt_init(&cd, action_argv[0])))
goto out;
......@@ -319,9 +330,8 @@ static int action_loopaesOpen(int arg __attribute__((unused)))
if (r < 0)
goto out;
r = crypt_activate_by_keyfile(cd, action_argv[1],
CRYPT_ANY_SLOT, opt_key_file, opt_keyfile_size,
opt_readonly ? CRYPT_ACTIVATE_READONLY : 0);
r = crypt_activate_by_keyfile(cd, action_argv[1], CRYPT_ANY_SLOT,
opt_key_file, opt_keyfile_size, activate_flags);
out:
crypt_free(cd);
......@@ -401,6 +411,8 @@ static int action_status(int arg __attribute__((unused)))
log_std(" skipped: %" PRIu64 " sectors\n", cad.iv_offset);
log_std(" mode: %s\n", cad.flags & CRYPT_ACTIVATE_READONLY ?
"readonly" : "read/write");
if (cad.flags & CRYPT_ACTIVATE_ALLOW_DISCARDS)
log_std(" flags: discards\n");
}
out:
crypt_free(cd);
......@@ -522,9 +534,13 @@ static int action_luksOpen(int arg __attribute__((unused)))
if (opt_iteration_time)
crypt_set_iterarion_time(cd, opt_iteration_time);
if (opt_readonly)
flags |= CRYPT_ACTIVATE_READONLY;
if (opt_allow_discards)
flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
if (opt_key_file) {
crypt_set_password_retry(cd, 1);
r = crypt_activate_by_keyfile(cd, action_argv[1],
......@@ -1138,7 +1154,8 @@ int main(int argc, const char **argv)
{ "use-random", '\0', POPT_ARG_NONE, &opt_random, 0, N_("Use /dev/random for generating volume key."), NULL },
{ "use-urandom", '\0', POPT_ARG_NONE, &opt_urandom, 0, N_("Use /dev/urandom for generating volume key."), NULL },
{ "shared", '\0', POPT_ARG_NONE, &opt_shared, 0, N_("Share device with another non-overlapping crypt segment."), NULL },
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use."), NULL },
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use."), NULL },
{ "allow-discards", '\0', POPT_ARG_NONE, &opt_allow_discards, 0, N_("Allow discards (aka TRIM) requests for device."), NULL },
POPT_TABLEEND
};
poptContext popt_context;
......@@ -1225,6 +1242,15 @@ int main(int argc, const char **argv)
poptGetInvocationName(popt_context));
}
if (opt_allow_discards &&
strcmp(aname, "luksOpen") &&
strcmp(aname, "create") &&
strcmp(aname, "loopaesOpen")) {
usage(popt_context, EXIT_FAILURE,
_("Option --allow-discards is allowed only for luksOpen, loopaesOpen and create operation.\n"),
poptGetInvocationName(popt_context));
}
if (opt_key_size &&
strcmp(aname, "luksFormat") &&
strcmp(aname, "create") &&
......
TESTS = api-test compat-test loopaes-test align-test mode-test password-hash-test
TESTS = api-test compat-test loopaes-test align-test discards-test mode-test password-hash-test
EXTRA_DIST = compatimage.img.bz2 \
compat-test loopaes-test align-test mode-test password-hash-test
compat-test loopaes-test align-test discards-test mode-test password-hash-test
differ_SOURCES = differ.c
differ_CFLAGS = -Wall -O2
......
#!/bin/bash
CRYPTSETUP="../src/cryptsetup"
DEV_NAME="discard-t3st"
DEV=""
cleanup() {
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME
udevadm settle >/dev/null 2>&1
rmmod scsi_debug 2>/dev/null
sleep 2
}
fail()
{
echo "FAILED"
cleanup
exit 100
}
add_device() {
modprobe scsi_debug $@
if [ $? -ne 0 ] ; then
echo "This kernel seems to not support proper scsi_debug module, test skipped."
exit 0
fi
sleep 2
DEV=$(grep scsi_debug /sys/block/*/device/model | cut -f4 -d /)
DEV="/dev/$DEV"
[ -b $DEV ] || fail "Cannot find $DEV."
}
function check_version()
{
VER_STR=$(dmsetup targets | grep crypt | cut -f 2 -dv)
VER_MAJ=$(echo $VER_STR | cut -f 1 -d.)
VER_MIN=$(echo $VER_STR | cut -f 2 -d.)
# option supported in 1.11
test $VER_MAJ -gt 1 && return 0
test $VER_MIN -ge 11 && return 0
return 1
}
if [ $(id -u) != 0 ]; then
echo "WARNING: You must be root to run this test, test skipped."
exit 0
fi
modprobe --dry-run scsi_debug || exit 0
modprobe dm-crypt >/dev/null 2>&1
if ! check_version ; then
echo "Probably old kernel, test skipped."
exit 0
fi
add_device dev_size_mb=16 sector_size=512 num_tgts=1 lbpu=1
# FIXME test hash of device (unmap -> zero)
# for now just check that flag is enabled
echo "[1] Allowing discards for LUKS device"
echo xxx | $CRYPTSETUP luksFormat $DEV -q -i1 || fail
echo xxx | $CRYPTSETUP luksOpen $DEV $DEV_NAME --allow-discards || fail
$CRYPTSETUP status $DEV_NAME | grep flags | grep discards >/dev/null || fail
$CRYPTSETUP resize $DEV_NAME --size 100 || fail
$CRYPTSETUP status $DEV_NAME | grep flags | grep discards >/dev/null || fail
dmsetup table $DEV_NAME | grep allow_discards >/dev/null || fail
$CRYPTSETUP luksClose $DEV_NAME || fail
echo "[2] Allowing discards for plain device"
echo xxx | $CRYPTSETUP create $DEV_NAME $DEV --allow-discards || fail
$CRYPTSETUP status $DEV_NAME | grep flags | grep discards >/dev/null || fail
$CRYPTSETUP resize $DEV_NAME --size 100 || fail
$CRYPTSETUP status $DEV_NAME | grep flags | grep discards >/dev/null || fail
dmsetup table $DEV_NAME | grep allow_discards >/dev/null || fail
$CRYPTSETUP remove $DEV_NAME || fail
cleanup
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