From b944dd4a3c74f497455c202f315b41761c568802 Mon Sep 17 00:00:00 2001 From: Renata Ravanelli Date: Thu, 30 Mar 2023 15:19:44 -0300 Subject: [PATCH] overlay.d: Add/Update udev rules for GCP - This PR injects/updates the udev rules from google-guest-config package into our overlay (GoogleCloudPlatform/guest-configs@18fbc05). - It works as an workaround for the BZ #2176212. The longer term solution is to add these packages as part of the Fedora/RHEL itself, so we won't need to maintain it, as we can entirely drop it. For this matter the BZ https://bugzilla.redhat.com/show_bug.cgi?id=2182865 was opened requesting a subpackage of google-compute-engine-guest-configs containing only what is needed. For more info: https://bugzilla.redhat.com/show_bug.cgi?id=2176212 https://github.com/GoogleCloudPlatform/guest-configs/tree/master/src/lib/udev Signed-off-by: Renata Ravanelli --- .../usr/lib/udev/google_nvme_id | 308 ++++++++++++++++++ .../udev/rules.d/64-gce-disk-removal.rules | 19 ++ .../lib/udev/rules.d/65-gce-disk-naming.rules | 31 +- 3 files changed, 344 insertions(+), 14 deletions(-) create mode 100644 overlay.d/30gcp-udev-rules/usr/lib/udev/google_nvme_id create mode 100644 overlay.d/30gcp-udev-rules/usr/lib/udev/rules.d/64-gce-disk-removal.rules diff --git a/overlay.d/30gcp-udev-rules/usr/lib/udev/google_nvme_id b/overlay.d/30gcp-udev-rules/usr/lib/udev/google_nvme_id new file mode 100644 index 0000000000..a41cd340e3 --- /dev/null +++ b/overlay.d/30gcp-udev-rules/usr/lib/udev/google_nvme_id @@ -0,0 +1,308 @@ +#!/bin/bash +# ATTENTION: This is a copy from https://github.com/GoogleCloudPlatform/guest-configs/blob/18fbc050b135461879e631a5ec2dd2cd7259d8e2/src/lib/udev/google_nvme_id + +# Copyright 2020 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Used to generate symlinks for NVMe devices (both local SSD and +# persistent disk) using the disk names reported by the metadata server. + + + +# Locations of the script's dependencies +readonly nvme_cli_bin=/usr/sbin/nvme + +# Bash regex to parse device paths and controller identification +readonly PD_CONTROLLER_REGEX="nvme_card-pd" +readonly SSD_CONTROLLER_REGEX="nvme_card[0-9]*" +readonly CONTROLLER_NUMBER_REGEX="nvme_card([[:digit:]]+)" +readonly NAMESPACE_NUMBER_REGEX="/dev/nvme[[:digit:]]+n([[:digit:]]+).*" +readonly PARTITION_NUMBER_REGEX="/dev/nvme[[:digit:]]+n[[:digit:]]+p([[:digit:]]+)" +readonly PD_NVME_REGEX="sn[[:space:]]+:[[:space]]+nvme_card-pd" + +# Globals used to generate the symlinks for a NVMe disk. These are populated +# by the identify_pd_disk function and exported for consumption by udev rules. +ID_SERIAL='' +ID_SERIAL_SHORT='' + +####################################### +# Helper function to log an error message to stderr. +# Globals: +# None +# Arguments: +# String to print as the log message +# Outputs: +# Writes error to STDERR +####################################### +function err() { + echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2 +} + +####################################### +# Retrieves the device name for an NVMe namespace using nvme-cli. +# Globals: +# Uses nvme_cli_bin +# Arguments: +# The path to the nvme namespace (/dev/nvme0n?) +# Outputs: +# The device name parsed from the JSON in the vendor ext of the ns-id command. +# Returns: +# 0 if the device name for the namespace could be retrieved, 1 otherwise +####################################### +function get_namespace_device_name() { + local nvme_json + nvme_json="$("$nvme_cli_bin" id-ns -b "$1" | xxd -p -seek 384 | xxd -p -r)" + if [[ $? -ne 0 ]]; then + return 1 + fi + + if [[ -z "$nvme_json" ]]; then + err "NVMe Vendor Extension disk information not present" + return 1 + fi + + local device_name + device_name="$(echo "$nvme_json" | grep device_name | sed -e 's/.*"device_name":[ \t]*"\([a-zA-Z0-9_-]\+\)".*/\1/')" + + # Error if our device name is empty + if [[ -z "$device_name" ]]; then + err "Empty name" + return 1 + fi + + echo "$device_name" + return 0 +} + +####################################### +# Retrieves the nsid for an NVMe namespace +# Globals: +# None +# Arguments: +# The path to the nvme namespace (/dev/nvme0n*) +# Outputs: +# The namespace number/id +# Returns: +# 0 if the namespace id could be retrieved, 1 otherwise +####################################### +function get_namespace_number() { + local dev_path="$1" + local namespace_number + if [[ "$dev_path" =~ $NAMESPACE_NUMBER_REGEX ]]; then + namespace_number="${BASH_REMATCH[1]}" + else + return 1 + fi + + echo "$namespace_number" + return 0 +} + +####################################### +# Retrieves the partition number for a device path if it exists +# Globals: +# None +# Arguments: +# The path to the device partition (/dev/nvme0n*p*) +# Outputs: +# The value after 'p' in the device path, or an empty string if the path has +# no partition. +####################################### +function get_partition_number() { + local dev_path="$1" + local partition_number + if [[ "$dev_path" =~ $PARTITION_NUMBER_REGEX ]]; then + partition_number="${BASH_REMATCH[1]}" + echo "$partition_number" + else + echo '' + fi + return 0 +} + +####################################### +# Retrieves the controller number from the device model if it exists +# Globals: +# None +# Arguments: +# The NVMe device model (nvme_card or nvme_card1/2/3/...) +# Outputs: +# The controller id/number +####################################### +function get_controller_number() { + local dev_model="$1" + local controller_number + if [[ "$dev_model" =~ $CONTROLLER_NUMBER_REGEX ]]; then + controller_number="${BASH_REMATCH[1]}" + echo "$controller_number" + else + # if it's 'nvme_card', echo 0. This is for backward compatibility. + echo '0' + fi + return 0 +} + +####################################### +# Generates a symlink for a PD-NVMe device using the metadata's disk name. +# Primarily used for testing but can be used if the script is directly invoked. +# Globals: +# Uses ID_SERIAL_SHORT (can be populated by identify_pd_disk) +# Arguments: +# The device path for the disk +####################################### +function gen_symlink() { + local dev_path="$1" + local partition_number="$(get_partition_number "$dev_path")" + + if [[ -n "$partition_number" ]]; then + ln -s "$dev_path" /dev/disk/by-id/google-"$ID_SERIAL_SHORT"-part"$partition_number" > /dev/null 2>&1 + else + ln -s "$dev_path" /dev/disk/by-id/google-"$ID_SERIAL_SHORT" > /dev/null 2>&1 + fi + + return 0 +} + +####################################### +# Populates the ID_* global variables with a disk's device name and namespace +# Globals: +# Populates ID_SERIAL_SHORT, and ID_SERIAL +# Arguments: +# The device path for the disk +# Returns: +# 0 on success and 1 if an error occurs +####################################### +function identify_pd_disk() { + local dev_path="$1" + local dev_name + dev_name="$(get_namespace_device_name "$dev_path")" + if [[ $? -ne 0 ]]; then + return 1 + fi + + ID_SERIAL_SHORT="$dev_name" + ID_SERIAL="Google_PersistentDisk_${ID_SERIAL_SHORT}" + return 0 +} + +####################################### +# Populates the ID_* global variables with a disk's device name and namespace +# Globals: +# Populates ID_SERIAL_SHORT, and ID_SERIAL +# Arguments: +# The device path for the disk +# Returns: +# 0 on success and 1 if an error occurs +####################################### +function identify_local_ssd_disk() { + local dev_model="$1" + local dev_path="$2" + local controller_number + controller_number="$(get_controller_number "$dev_model")" + if [[ $? -ne 0 ]]; then + return 1 + fi + + local namespace_number + namespace_number="$(get_namespace_number "$dev_path")" + if [[ $? -ne 0 ]]; then + return 1 + fi + + ID_SERIAL_SHORT="local-nvme-ssd-$(($controller_number+$namespace_number-1))" + ID_SERIAL="Google_EphemeralDisk_${ID_SERIAL_SHORT}" + return 0 +} + +function print_help_message() { + echo "Usage: google_nvme_id [-s] [-h] -d device_path" + echo " -d (Required): Specifies the path to generate a name" + echo " for. This needs to be a path to an nvme device or namespace" + echo " -s: Create symbolic link for the disk under /dev/disk/by-id." + echo " Otherwise, the disk name will be printed to STDOUT" + echo " -h: Print this help message" +} + +function main() { + local opt_gen_symlink='false' + local device_path='' + + while getopts :d:sh flag; do + case "$flag" in + d) device_path="$OPTARG";; + s) opt_gen_symlink='true';; + h) print_help_message + return 0 + ;; + :) echo "Invalid option: ${OPTARG} requires an argument" 1>&2 + return 1 + ;; + *) return 1 + esac + done + + if [[ -z "$device_path" ]]; then + echo "Device path (-d) argument required. Use -h for full usage." 1>&2 + exit 1 + fi + + # Ensure the nvme-cli command is installed + command -v "$nvme_cli_bin" > /dev/null 2>&1 + if [[ $? -ne 0 ]]; then + err "The nvme utility (/usr/sbin/nvme) was not found. You may need to run \ +with sudo or install nvme-cli." + return 1 + fi + + # Ensure the passed device is actually an NVMe device + "$nvme_cli_bin" id-ctrl "$device_path" &>/dev/null + if [[ $? -ne 0 ]]; then + err "Passed device was not an NVMe device. (You may need to run this \ +script as root/with sudo)." + return 1 + fi + + # Detect the type of attached nvme device + local controller_id + controller_id=$("$nvme_cli_bin" id-ctrl "$device_path") + if [[ "$controller_id" =~ $PD_CONTROLLER_REGEX ]] ; then + # Fill the global variables for the id command for the given disk type + # Error messages will be printed closer to error, no need to reprint here + identify_pd_disk "$device_path" + if [[ $? -ne 0 ]]; then + return $? + fi + elif [[ "$controller_id" =~ $SSD_CONTROLLER_REGEX ]] ; then + identify_local_ssd_disk "$controller_id" "$device_path" + if [[ $? -ne 0 ]]; then + return $? + fi + else + err "Device is not a NVMe device" + return 1 + fi + + # Gen symlinks or print out the globals set by the identify command + if [[ "$opt_gen_symlink" == 'true' ]]; then + gen_symlink "$device_path" + else + # These will be consumed by udev + echo "ID_SERIAL_SHORT=${ID_SERIAL_SHORT}" + echo "ID_SERIAL=${ID_SERIAL}" + fi + + return $? + +} +main "$@" diff --git a/overlay.d/30gcp-udev-rules/usr/lib/udev/rules.d/64-gce-disk-removal.rules b/overlay.d/30gcp-udev-rules/usr/lib/udev/rules.d/64-gce-disk-removal.rules new file mode 100644 index 0000000000..052d636b21 --- /dev/null +++ b/overlay.d/30gcp-udev-rules/usr/lib/udev/rules.d/64-gce-disk-removal.rules @@ -0,0 +1,19 @@ +# ATTENTION: It is a copy from https://github.com/GoogleCloudPlatform/guest-configs/blob/18fbc050b135461879e631a5ec2dd2cd7259d8e2/src/lib/udev/rules.d/64-gce-disk-removal.rules +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# When a disk is removed, unmount any remaining attached volumes. + +ACTION=="remove", SUBSYSTEM=="block", KERNEL=="sd*|vd*|nvme*", RUN+="/bin/sh -c '/bin/umount -fl /dev/$name && /usr/bin/logger -p daemon.warn -s WARNING: hot-removed /dev/$name that was still mounted, data may have been corrupted'" diff --git a/overlay.d/30gcp-udev-rules/usr/lib/udev/rules.d/65-gce-disk-naming.rules b/overlay.d/30gcp-udev-rules/usr/lib/udev/rules.d/65-gce-disk-naming.rules index e19c1c5b91..5c62b7564d 100644 --- a/overlay.d/30gcp-udev-rules/usr/lib/udev/rules.d/65-gce-disk-naming.rules +++ b/overlay.d/30gcp-udev-rules/usr/lib/udev/rules.d/65-gce-disk-naming.rules @@ -1,3 +1,4 @@ +# ATTENTION: It is a copy from https://github.com/GoogleCloudPlatform/guest-configs/blob/18fbc050b135461879e631a5ec2dd2cd7259d8e2/src/lib/udev/rules.d/65-gce-disk-naming.rules # Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,27 +13,29 @@ # See the License for the specific language governing permissions and # limitations under the License. # + # Name the attached disks as the specified by deviceName. ACTION!="add|change", GOTO="gce_disk_naming_end" SUBSYSTEM!="block", GOTO="gce_disk_naming_end" # SCSI naming -KERNEL=="sd*|vd*", ENV{ID_VENDOR}=="Google", IMPORT{program}="scsi_id --export --whitelisted -d $tempnode" - -# NVME naming -KERNEL=="nvme0n1*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-0" -KERNEL=="nvme0n2*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-1" -KERNEL=="nvme0n3*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-2" -KERNEL=="nvme0n4*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-3" -KERNEL=="nvme0n5*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-4" -KERNEL=="nvme0n6*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-5" -KERNEL=="nvme0n7*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-6" -KERNEL=="nvme0n8*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-7" -KERNEL=="nvme*", ENV{ID_VENDOR}=="Google", ENV{ID_SERIAL}="Google_EphemeralDisk_$env{ID_SERIAL_SHORT}" +KERNEL=="sd*|vd*", IMPORT{program}="scsi_id --export --whitelisted -d $tempnode" + +# NVME Local SSD naming +KERNEL=="nvme*n*", ATTRS{model}=="nvme_card", PROGRAM="/bin/sh -c 'nsid=$$(echo %k|sed -re s/nvme[0-9]+n\([0-9]+\).\*/\\1/); echo $$((nsid-1))'", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-%c" +KERNEL=="nvme*", ATTRS{model}=="nvme_card", ENV{ID_SERIAL}="Google_EphemeralDisk_$env{ID_SERIAL_SHORT}" +# Support for local SSD multi-controller +KERNEL=="nvme*n*", ATTRS{model}=="nvme_card[0-9]*", IMPORT{program}="google_nvme_id -d $tempnode" + +# NVME Persistent Disk IO Timeout +KERNEL=="nvme*n*", ENV{DEVTYPE}=="disk", ATTRS{model}=="nvme_card-pd", ATTR{queue/io_timeout}="4294967295" + +# NVME Persistent Disk Naming +KERNEL=="nvme*n*", ATTRS{model}=="nvme_card-pd", IMPORT{program}="google_nvme_id -d $tempnode" # Symlinks -KERNEL=="sd*|vd*|nvme*", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="Google", SYMLINK+="disk/by-id/google-$env{ID_SERIAL_SHORT}" -KERNEL=="sd*|vd*|nvme*", ENV{DEVTYPE}=="partition", ENV{ID_VENDOR}=="Google", SYMLINK+="disk/by-id/google-$env{ID_SERIAL_SHORT}-part%n" +KERNEL=="sd*|vd*|nvme*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/google-$env{ID_SERIAL_SHORT}" +KERNEL=="sd*|vd*|nvme*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/google-$env{ID_SERIAL_SHORT}-part%n" LABEL="gce_disk_naming_end"