Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support OPAL 2 self-encrypting NVMe disk drives (fix #2475) #2488

Merged
merged 5 commits into from
Nov 5, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion usr/share/rear/lib/layout-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,9 @@ generate_layout_dependencies() {
opaldisk)
dev=$(echo "$remainder" | cut -d " " -f "1")
add_component "opaldisk:$dev" "opaldisk"
add_dependency "$dev" "opaldisk:$dev"
for disk in $(opal_device_disks "$dev"); do
add_dependency "$disk" "opaldisk:$dev"
done
;;
esac
done < $LAYOUT_FILE
Expand Down
26 changes: 21 additions & 5 deletions usr/share/rear/lib/opal-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

#
# Functions in this section are meant to be used independently from ReaR. They do not rely on any external
# script code unless. Return codes must be checked by the caller.
# script code unless stated otherwise. Return codes must be checked by the caller.
#

function opal_devices() {
Expand All @@ -26,6 +26,22 @@ function opal_devices() {
sedutil-cli --scan | awk '$1 ~ /\/dev\// && $2 ~ /2/ { print $1; }'
}

function opal_device_disks() {
local device="${1:?}"
# prints all block devices belonging to the given Opal device.
# Normally, this is just the Opal device itself, however, NVME devices have one or more namespaces per primary
# device and these namespaces act as disks.

case "$device" in
(*/nvme*)
echo "$device"n[0-9] # consider all namespace block devices (NOTE: relies on nullglob)
Copy link
Member

@jsmeix jsmeix Sep 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"$device"n[0-9] matches only up to namespace number 9 i.e. /dev/nvme...n9
so e.g. /dev/nvme0n10 and higher namespace numbers are ignored.

To be more on the safe side I suggest

# consider all namespace block devices up to /dev/nvme...n99 (NOTE: relies on nullglob)
echo "$device"n[1-9] "$device"n[1-9][0-9]

I think more than 9 namespaces might happen in practice
while more than 99 namespaces never happen in real world.

But the latter is probably only wishful thinking because
https://nvmexpress.org/wp-content/uploads/NVM-Express-1_4-2019.06.10-Ratified.pdf
reads (excerpts)

... namespace ID (NSID) ...

6.1.2 Valid and Invalid NSIDs
...
Any NSID is valid, except if that NSID is 0h or greater than the
Number of Namespaces field reported in the Identify Controller
data structure (refer to Figure 247).
NSID FFFFFFFFh is a broadcast value that is used to specify
all namespaces. 

so it seems any number up to FFFFFFFFh could appear in real world.

Copy link
Member

@jsmeix jsmeix Sep 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The next question is how namespaces > 9 block device nodes are shown:
As decimal numbers like /dev/nvme0n12
or as hex numbers like /dev/nvme0nc or /dev/nvme0nC or /dev/nvme0n0c

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far, I have not seen namespace IDs beyond 1 being used in the wild. But I don't mind if we extend the scheme.

The kernel will use decimal digits:

	sprintf(disk_name, "nvme%dn%d", ctrl->instance, ns->head->instance);

;;
(*)
echo "$device"
;;
esac
}

function opal_device_attributes() {
local device="${1:?}"
local result_variable_name="${2:?}"
Expand Down Expand Up @@ -140,15 +156,15 @@ function opal_device_regenerate_dek_ERASING_ALL_DATA() {
# This is recommended initially to ensure that the data encryption key is not known by any third party.
# Returns 0 on success.

sedutil-cli --rekeyLockingRange 0 "$password" "$device" && partprobe "$device"
sedutil-cli --rekeyLockingRange 0 "$password" "$device" && partprobe $(opal_device_disks "$device")
}

function opal_device_factory_reset_ERASING_ALL_DATA() {
local device="${1:?}"
local password="${2:?}"
# factory-resets the device, ERASING ALL DATA ON THE DRIVE, returns 0 on success

sedutil-cli --reverttper "$password" "$device" && partprobe "$device"
sedutil-cli --reverttper "$password" "$device" && partprobe $(opal_device_disks "$device")
}

function opal_device_load_pba_image() {
Expand All @@ -172,7 +188,7 @@ function opal_device_disable_mbr() {
local password="${2:?}"
# disables the device's shadow MBR, returns 0 on success.

sedutil-cli --setMBREnable off "$password" "$device" && partprobe "$device"
sedutil-cli --setMBREnable off "$password" "$device" && partprobe $(opal_device_disks "$device")
}

function opal_device_enable_mbr() {
Expand All @@ -189,7 +205,7 @@ function opal_device_hide_mbr() {
# hides the device's shadow MBR if one has been enabled, does nothing otherwise.
# Returns 0 on success.

sedutil-cli --setMBRDone on "$password" "$device" && partprobe "$device"
sedutil-cli --setMBRDone on "$password" "$device" && partprobe $(opal_device_disks "$device")
}

function opal_device_unlock() {
Expand Down