Skip to content

Commit

Permalink
Add persistent and perf options to the luks_device (#434)
Browse files Browse the repository at this point in the history
Read and write work queue significantly degrades performance on
SSD/NVME devices[1].

In Debian 11 crypttab does not support no-read-workqueue and
no-write-workqueue flags, so the persistent flag is workaround: once
opened with perf parameters persists forever.

[1] https://blog.cloudflare.com/speeding-up-linux-disk-encryption/

Signed-off-by: Yauhen Artsiukhou <[email protected]>
  • Loading branch information
jsirex authored Apr 10, 2022
1 parent c7f581d commit 041fff5
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 1 deletion.
4 changes: 4 additions & 0 deletions changelogs/fragments/434-add-persistent-and-perf-options.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
minor_changes:
- luks_devices - added ``persistent`` option when opening LUKS2 containers (https://github.com/ansible-collections/community.crypto/pull/434).
- luks_devices - added ``perf_same_cpu_crypt``, ``perf_submit_from_crypt_cpus``, ``perf_no_read_workqueue``, ``perf_no_write_workqueue`` for performance tuning when opening LUKS2 containers (https://github.com/ansible-collections/community.crypto/issues/427).
65 changes: 64 additions & 1 deletion plugins/modules/luks_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,48 @@
- "Will only be used on container creation."
type: int
version_added: '1.5.0'
perf_same_cpu_crypt:
description:
- "Allows the user to perform encryption using the same CPU that IO was submitted on."
- "The default is to use an unbound workqueue so that encryption work is automatically balanced between available CPUs."
- "Will only be used when opening containers."
type: bool
default: false
version_added: '2.3.0'
perf_submit_from_crypt_cpus:
description:
- "Allows the user to disable offloading writes to a separate thread after encryption."
- "There are some situations where offloading block write IO operations from the encryption threads
to a single thread degrades performance significantly."
- "The default is to offload block write IO operations to the same thread."
- "Will only be used when opening containers."
type: bool
default: false
version_added: '2.3.0'
perf_no_read_workqueue:
description:
- "Allows the user to bypass dm-crypt internal workqueue and process read requests synchronously."
- "Will only be used when opening containers."
type: bool
default: false
version_added: '2.3.0'
perf_no_write_workqueue:
description:
- "Allows the user to bypass dm-crypt internal workqueue and process write requests synchronously."
- "Will only be used when opening containers."
type: bool
default: false
version_added: '2.3.0'
persistent:
description:
- "Allows the user to store options into container's metadata persistently and automatically use them next time.
Only I(perf_same_cpu_crypt), I(perf_submit_from_crypt_cpus), I(perf_no_read_workqueue), and I(perf_no_write_workqueue)
can be stored persistently."
- "Will only work with LUKS2 containers."
- "Will only be used when opening containers."
type: bool
default: false
version_added: '2.3.0'
requirements:
- "cryptsetup"
Expand Down Expand Up @@ -517,10 +559,21 @@ def run_luks_create(self, device, keyfile, passphrase, keysize, cipher, hash_, s
raise ValueError('Error while creating LUKS on %s: %s'
% (device, result[STDERR]))

def run_luks_open(self, device, keyfile, passphrase, name):
def run_luks_open(self, device, keyfile, passphrase, perf_same_cpu_crypt, perf_submit_from_crypt_cpus,
perf_no_read_workqueue, perf_no_write_workqueue, persistent, name):
args = [self._cryptsetup_bin]
if keyfile:
args.extend(['--key-file', keyfile])
if perf_same_cpu_crypt:
args.extend(['--perf-same_cpu_crypt'])
if perf_submit_from_crypt_cpus:
args.extend(['--perf-submit_from_crypt_cpus'])
if perf_no_read_workqueue:
args.extend(['--perf-no_read_workqueue'])
if perf_no_write_workqueue:
args.extend(['--perf-no_write_workqueue'])
if persistent:
args.extend(['--persistent'])
args.extend(['open', '--type', 'luks', device, name])

result = self._run_command(args, data=passphrase)
Expand Down Expand Up @@ -802,6 +855,11 @@ def run_module():
mutually_exclusive=[('iteration_time', 'iteration_count')],
),
sector_size=dict(type='int'),
perf_same_cpu_crypt=dict(type='bool', default=False),
perf_submit_from_crypt_cpus=dict(type='bool', default=False),
perf_no_read_workqueue=dict(type='bool', default=False),
perf_no_write_workqueue=dict(type='bool', default=False),
persistent=dict(type='bool', default=False),
)

mutually_exclusive = [
Expand Down Expand Up @@ -877,6 +935,11 @@ def run_module():
crypt.run_luks_open(conditions.device,
module.params['keyfile'],
module.params['passphrase'],
module.params['perf_same_cpu_crypt'],
module.params['perf_submit_from_crypt_cpus'],
module.params['perf_no_read_workqueue'],
module.params['perf_no_write_workqueue'],
module.params['persistent'],
name)
except ValueError as e:
module.fail_json(msg="luks_device error: %s" % e)
Expand Down
103 changes: 103 additions & 0 deletions tests/integration/targets/luks_device/tasks/tests/performance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
- name: Gather package facts
package_facts:
manager: auto

- name: On kernel >= 5.9 use performance flags
block:
- name: Create and open (check)
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ remote_tmp_dir }}/keyfile1"
perf_same_cpu_crypt: true
perf_submit_from_crypt_cpus: true
perf_no_read_workqueue: true
perf_no_write_workqueue: true
persistent: true
pbkdf:
iteration_time: 0.1
check_mode: yes
become: yes
register: create_open_check
- name: Create and open
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
perf_same_cpu_crypt: true
perf_submit_from_crypt_cpus: true
perf_no_read_workqueue: true
perf_no_write_workqueue: true
persistent: true
become: yes
register: create_open
- name: Create and open (idempotent)
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
perf_same_cpu_crypt: true
perf_submit_from_crypt_cpus: true
perf_no_read_workqueue: true
perf_no_write_workqueue: true
persistent: true
become: yes
register: create_open_idem
- name: Create and open (idempotent, check)
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
perf_same_cpu_crypt: true
perf_submit_from_crypt_cpus: true
perf_no_read_workqueue: true
perf_no_write_workqueue: true
persistent: true
check_mode: yes
become: yes
register: create_open_idem_check
- assert:
that:
- create_open_check is changed
- create_open is changed
- create_open_idem is not changed
- create_open_idem_check is not changed

- name: Dump LUKS Header
command: "cryptsetup luksDump {{ cryptfile_device }}"
become: yes
register: luks_header
- assert:
that:
- "'no-read-workqueue' in luks_header.stdout"
- "'no-write-workqueue' in luks_header.stdout"
- "'same-cpu-crypt' in luks_header.stdout"
- "'submit-from-crypt-cpus' in luks_header.stdout"

- name: Dump device mapper table
command: "dmsetup table {{ create_open.name }}"
become: yes
register: dm_table
- assert:
that:
- "'no_read_workqueue' in dm_table.stdout"
- "'no_write_workqueue' in dm_table.stdout"
- "'same_cpu_crypt' in dm_table.stdout"
- "'submit_from_crypt_cpus' in dm_table.stdout"

- name: Closed and Removed
luks_device:
name: "{{ cryptfile_device }}"
state: absent
become: yes

when:
- ansible_facts.kernel is version('5.9.0', '>=')
- ansible_facts.packages['cryptsetup'][0].version is version('2.3.4', '>=')

0 comments on commit 041fff5

Please sign in to comment.