add a new switch to control whether udev complies with the new SAT standards; add sense_data.py to check if the device meets the new SAT standards; fix compilation failure with - O0 option

This commit is contained in:
wangyuhang 2023-08-17 17:11:08 +08:00
parent fd7afec7d1
commit caecdd36fc
4 changed files with 439 additions and 2 deletions

View File

@ -0,0 +1,148 @@
From 18c373e2686a9156a701ad440507172ec8bb13a3 Mon Sep 17 00:00:00 2001
From: wangyuhang <wangyuhang27@huawei.com>
Date: Fri, 7 Jul 2023 16:11:01 +0800
Subject: [PATCH] Add a new switch to control whether udev complies with the
new SAT standards
Reason: Original revisions of the SAT (SCSI-ATA Translation) specification,
udev will identify devices starting with 70 and ending with 00 1d as ATA devices,
rather than scsi devices, which may have a change in wwn id and affect user usage.
So Add a new switch to control whether udev complies with the new SAT standards
---
src/shared/udev-util.c | 16 ++++++++++++++--
src/shared/udev-util.h | 5 +++--
src/udev/ata_id/ata_id.c | 19 +++++++++++++++++--
src/udev/udevd.c | 3 ++-
4 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c
index f934fc1..2ff4a7c 100644
--- a/src/shared/udev-util.c
+++ b/src/shared/udev-util.c
@@ -38,9 +38,11 @@ int udev_parse_config_full(
usec_t *ret_exec_delay_usec,
usec_t *ret_event_timeout_usec,
ResolveNameTiming *ret_resolve_name_timing,
- int *ret_timeout_signal) {
+ int *ret_timeout_signal,
+ bool *ret_ignore_newer_SAT) {
_cleanup_free_ char *log_val = NULL, *children_max = NULL, *exec_delay = NULL, *event_timeout = NULL, *resolve_names = NULL, *timeout_signal = NULL;
+ _cleanup_free_ char *ignore_newer_SAT = NULL;
int r;
r = parse_env_file(NULL, "/etc/udev/udev.conf",
@@ -49,7 +51,8 @@ int udev_parse_config_full(
"exec_delay", &exec_delay,
"event_timeout", &event_timeout,
"resolve_names", &resolve_names,
- "timeout_signal", &timeout_signal);
+ "timeout_signal", &timeout_signal,
+ "ignore_newer_SAT", &ignore_newer_SAT);
if (r == -ENOENT)
return 0;
if (r < 0)
@@ -118,6 +121,15 @@ int udev_parse_config_full(
*ret_timeout_signal = r;
}
+ if (ret_ignore_newer_SAT && ignore_newer_SAT) {
+ r = parse_boolean(ignore_newer_SAT);
+ if (r < 0)
+ log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r,
+ "failed to parse ignore_newer_SAT=%s, ignoring.", ignore_newer_SAT);
+ else
+ *ret_ignore_newer_SAT = r;
+ }
+
return 0;
}
diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h
index 276686d..9695c64 100644
--- a/src/shared/udev-util.h
+++ b/src/shared/udev-util.h
@@ -30,10 +30,11 @@ int udev_parse_config_full(
usec_t *ret_exec_delay_usec,
usec_t *ret_event_timeout_usec,
ResolveNameTiming *ret_resolve_name_timing,
- int *ret_timeout_signal);
+ int *ret_timeout_signal,
+ bool *ret_ignore_newer_SAT);
static inline int udev_parse_config(void) {
- return udev_parse_config_full(NULL, NULL, NULL, NULL, NULL);
+ return udev_parse_config_full(NULL, NULL, NULL, NULL, NULL, NULL);
}
int device_wait_for_initialization(sd_device *device, const char *subsystem, usec_t timeout_usec, sd_device **ret);
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
index 1fc27f4..10a3464 100644
--- a/src/udev/ata_id/ata_id.c
+++ b/src/udev/ata_id/ata_id.c
@@ -28,9 +28,13 @@
#include "log.h"
#include "memory-util.h"
#include "udev-util.h"
+#include "proc-cmdline.h"
+#include "string-util.h"
#define COMMAND_TIMEOUT_MSEC (30 * 1000)
+static bool arg_ignore_newer_SAT = false;
+
static int disk_scsi_inquiry_command(
int fd,
void *buf,
@@ -163,7 +167,7 @@ static int disk_identify_command(
}
if (!((sense[0] & 0x7f) == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c) &&
- !((sense[0] & 0x7f) == 0x70 && sense[12] == 0x00 && sense[13] == 0x1d)) {
+ (arg_ignore_newer_SAT || !((sense[0] & 0x7f) == 0x70 && sense[12] == 0x00 && sense[13] == 0x1d))) {
errno = EIO;
return -1;
}
@@ -407,12 +411,23 @@ int main(int argc, char *argv[]) {
{ "help", no_argument, NULL, 'h' },
{}
};
+ int r;
log_set_target(LOG_TARGET_AUTO);
- udev_parse_config();
+ udev_parse_config_full(NULL, NULL, NULL, NULL, NULL, &arg_ignore_newer_SAT);
log_parse_environment();
log_open();
+ /* When either ignore_newer_SAT in udev.conf or udev.ignore_newer_SAT in the kernel command line is true,
+ * set arg_ignore_newer_SAT to true and ignoring the new SAT standard
+ */
+ if (!arg_ignore_newer_SAT) {
+ r = proc_cmdline_get_bool("udev.ignore_newer_SAT", &arg_ignore_newer_SAT);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to parse udev.ignore_newer_SAT kernel command line argument, ignoring: %m");
+ }
+ }
+
for (;;) {
int option;
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 023fe55..34bc6ee 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -2073,7 +2073,8 @@ int run_udevd(int argc, char *argv[]) {
log_set_target(LOG_TARGET_AUTO);
log_open();
- udev_parse_config_full(&arg_children_max, &arg_exec_delay_usec, &arg_event_timeout_usec, &arg_resolve_name_timing, &arg_timeout_signal);
+ /* ignore_newer_SAT only valid in ata_id.c */
+ udev_parse_config_full(&arg_children_max, &arg_exec_delay_usec, &arg_event_timeout_usec, &arg_resolve_name_timing, &arg_timeout_signal, NULL);
log_parse_environment();
log_open(); /* Done again to update after reading configuration. */
--
2.33.0

View File

@ -10,12 +10,13 @@ logs). Therefore, when the journal~ file is generated, delete all journal files
except system.journal, to ensure that the sd_journal_next function meets user except system.journal, to ensure that the sd_journal_next function meets user
expectations. expectations.
--- ---
meson.build | 2 ++ meson.build | 3 ++-
src/basic/dirent-util.c | 24 +++++++++++++++++ src/basic/dirent-util.c | 24 +++++++++++++++++
src/basic/dirent-util.h | 2 ++ src/basic/dirent-util.h | 2 ++
src/libsystemd/sd-journal/journal-file.c | 34 ++++++++++++++++++++++++ src/libsystemd/sd-journal/journal-file.c | 34 ++++++++++++++++++++++++
src/libsystemd/sd-journal/sd-journal.c | 22 --------------- src/libsystemd/sd-journal/sd-journal.c | 22 ---------------
5 files changed, 62 insertions(+), 22 deletions(-) src/test/meson.build | 2 +-
6 files changed, 63 insertions(+), 23 deletions(-)
diff --git a/meson.build b/meson.build diff --git a/meson.build b/meson.build
index 0372b17..8b1ce23 100644 index 0372b17..8b1ce23 100644
@ -30,6 +31,15 @@ index 0372b17..8b1ce23 100644
'.') '.')
libsystemd_includes = [basic_includes, include_directories( libsystemd_includes = [basic_includes, include_directories(
@@ -1801,7 +1801,7 @@ test_dlopen = executable(
'test-dlopen',
test_dlopen_c,
include_directories : includes,
- link_with : [libbasic],
+ link_with : [libbasic, libsystemd_static],
dependencies : [libdl],
build_by_default : want_tests != 'false')
diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c
index 17df6a2..e362554 100644 index 17df6a2..e362554 100644
--- a/src/basic/dirent-util.c --- a/src/basic/dirent-util.c

267
sense_data.py Normal file
View File

@ -0,0 +1,267 @@
#!/usr/bin/env python
import sys
import os
import re
import ctypes
import fcntl
import string
MEET_NEWER_SAT = 0
wwn = ctypes.c_uint64()
BSG_PROTOCOL_SCSI = 0 # <linux/bsg.h>
BSG_SUB_PROTOCOL_SCSI_CMD = 0 # <linux/bsg.h>
SG_DXFER_FROM_DEV = -3 # SCSI READ command
ASCII_S = 83 # 'S'
ASCII_Q = 81 # 'Q'
SG_IO = 0x2285 # <scsi/sg.h>
"""
INQUIRY Command
https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
3.6.1 Section
"""
class inquiry_cmd(ctypes.Structure):
_pack_ = 1
_fields_ = [
("opcode", ctypes.c_ubyte),
("reserved", ctypes.c_ubyte),
("pagecode", ctypes.c_ubyte),
("alloc_len_3", ctypes.c_ubyte),
("alloc_len_4", ctypes.c_ubyte),
("control", ctypes.c_ubyte)
]
"""
ATA PASS-THROUGH (12) command
https://www.t10.org/ftp/t10/document.04/04-262r8.pdf
13.2.2 Section
"""
class ata_cmd_12(ctypes.Structure):
_pack_ = 1
_fields_ = [
("opcode", ctypes.c_ubyte),
("protocol", ctypes.c_ubyte),
("flags", ctypes.c_ubyte),
("features", ctypes.c_ubyte),
("sector_count", ctypes.c_ubyte),
("lba_low", ctypes.c_ubyte),
("lba_mid", ctypes.c_ubyte),
("lba_high", ctypes.c_ubyte),
("device", ctypes.c_ubyte),
("command", ctypes.c_ubyte),
("reserved", ctypes.c_ubyte),
("control", ctypes.c_ubyte)
]
"""
ref: include/scsi/sg.h
"""
class sgio_hdr(ctypes.Structure):
_pack_ = 1
_fields_ = [
# [i] 'S' for SCSI generic (required)
("interface_id", ctypes.c_int),
("dxfer_direction", ctypes.c_int), # [i] data transfer direction
# [i] SCSI command length ( <= 16 bytes)
("cmd_len", ctypes.c_ubyte),
("mx_sb_len", ctypes.c_ubyte), # [i] max length to write to sbp
("iovec_count", ctypes.c_ushort), # [i] 0 implies no scatter gather
("dxfer_len", ctypes.c_uint), # [i] byte count of data transfer
# [i], [*io] points to data transfer memory
("dxferp", ctypes.c_void_p),
# [i], [*i] points to command to perform
("cmdp", ctypes.c_void_p),
# [i], [*o] points to sense_buffer memory
("sbp", ctypes.c_void_p),
# [i] MAX_UINT->no timeout (unit: millisec)
("timeout", ctypes.c_uint),
("flags", ctypes.c_uint), # [i] 0 -> default, see SG_FLAG...
# [i->o] unused internally (normally)
("pack_id", ctypes.c_int),
("usr_ptr", ctypes.c_void_p), # [i->o] unused internally
("status", ctypes.c_ubyte), # [o] scsi status
("masked_status", ctypes.c_ubyte), # [o] shifted, masked scsi status
# [o] messaging level data (optional)
("msg_status", ctypes.c_ubyte),
# [o] byte count actually written to sbp
("sb_len_wr", ctypes.c_ubyte),
("host_status", ctypes.c_ushort), # [o] errors from host adapter
("driver_status", ctypes.c_ushort), # [o] errors from software driver
# [o] dxfer_len - actual_transferred
("resid", ctypes.c_int),
# [o] time taken by cmd (unit: millisec)
("duration", ctypes.c_uint),
("info", ctypes.c_uint) # [o] auxiliary information
]
def from_bytes(bytes_in_array, byteorder="big", signed=False):
if byteorder == "little":
little_ordered = list(bytes_in_array)
elif byteorder == "big":
little_ordered = list(reversed(bytes_in_array))
else:
raise ValueError("byteorder must be either 'little' or 'big'")
n = sum(b << i*8 for i, b in enumerate(little_ordered))
if signed and little_ordered and (little_ordered[-1] & 0x80):
n -= 1 << 8*len(little_ordered)
return n
def disk_scsi_inquiry_command(dev, buf):
sense = ctypes.c_buffer(32)
buf_len = ctypes.sizeof(buf)
cdb = inquiry_cmd(opcode=0x12,
reserved=0,
pagecode=0,
alloc_len_3=(buf_len >> 8),
alloc_len_4=(buf_len & 0xff),
control=0)
# systemd first tries to identify the disk by version 4, but failed. We directly use version3
io_hdr = sgio_hdr(interface_id=ASCII_S, dxfer_direction=SG_DXFER_FROM_DEV,
cmd_len=ctypes.sizeof(cdb),
mx_sb_len=ctypes.sizeof(sense), iovec_count=0,
dxfer_len=buf_len,
dxferp=ctypes.cast(buf, ctypes.c_void_p),
cmdp=ctypes.addressof(cdb),
sbp=ctypes.cast(sense, ctypes.c_void_p), timeout=30 * 1000,
flags=0, pack_id=0, usr_ptr=None, status=0, masked_status=0,
msg_status=0, sb_len_wr=0, host_status=0, driver_status=0,
resid=0, duration=0, info=0)
try:
with open(dev, "r") as fd:
ret = fcntl.ioctl(fd.fileno(), SG_IO, io_hdr)
if io_hdr.status != 0 or io_hdr.host_status != 0 or io_hdr.driver_status != 0 or ret != 0:
return False
except OSError as err:
return False
except IOError as err:
return False
return True
def disk_identify_command(dev, buf):
global MEET_NEWER_SAT
MEET_NEWER_SAT = 0
sense = ctypes.c_buffer(32)
buf_len = ctypes.sizeof(buf)
cdb = ata_cmd_12(opcode=0xa1, protocol=(4 << 1), flags=0x2e,
features=0, sector_count=1, lba_low=0, lba_mid=0, lba_high=0,
device=0 & 0x4F, command=0xEC, reserved=0, control=0)
# systemd first tries to identify the disk by version 4, but failed. We directly use version3
io_hdr = sgio_hdr(interface_id=ASCII_S, dxfer_direction=SG_DXFER_FROM_DEV,
cmd_len=ctypes.sizeof(cdb),
mx_sb_len=ctypes.sizeof(sense), iovec_count=0,
dxfer_len=buf_len,
dxferp=ctypes.cast(buf, ctypes.c_void_p),
cmdp=ctypes.addressof(cdb),
sbp=ctypes.cast(sense, ctypes.c_void_p), timeout=30 * 1000,
flags=0, pack_id=0, usr_ptr=None, status=0, masked_status=0,
msg_status=0, sb_len_wr=0, host_status=0, driver_status=0,
resid=0, duration=0, info=0)
try:
with open(dev, "r") as fd:
ret = fcntl.ioctl(fd.fileno(), SG_IO, io_hdr)
if ret != 0:
return False
except OSError as err:
return False
except IOError as err:
return False
if sense[0] == b'\x72' and sense[8] == b'\x09' and sense[9] == b'\x0c':
return True
if sense[0] == b'\x70' and sense[12] == b'\x00' and sense[13] == b'\x1d':
MEET_NEWER_SAT = 1
return True
return False
def disk_identify(dev):
identify = ctypes.c_buffer(512)
inquiry_buf = ctypes.c_buffer(36)
ret = disk_scsi_inquiry_command(dev=dev, buf=inquiry_buf)
if not ret:
return False
peripheral_device_type = from_bytes(
bytearray(inquiry_buf[0]), byteorder="little") & 0x1f
if peripheral_device_type == 0x05:
return False
if not (peripheral_device_type == 0x00 or peripheral_device_type == 0x14):
return False
if not disk_identify_command(dev=dev, buf=identify):
return False
global wwn
wwn = ctypes.c_uint64()
identify = bytearray(identify)
wwn = from_bytes(
[identify[108 * 2], identify[108 * 2 + 1]], byteorder="little")
wwn = wwn << 16
wwn |= from_bytes(
[identify[109 * 2], identify[109 * 2 + 1]], byteorder="little")
wwn = wwn << 16
wwn |= from_bytes(
[identify[110 * 2], identify[110 * 2 + 1]], byteorder="little")
wwn = wwn << 16
wwn |= from_bytes(
[identify[111 * 2], identify[111 * 2 + 1]], byteorder="little")
return True
def check_ata_disk():
ret = False
for filename in os.listdir("/dev/"):
if not re.match("sd.*[^0-9]$|sr.*", filename):
continue
if not disk_identify("/dev/"+filename):
continue
global MEET_NEWER_SAT
if MEET_NEWER_SAT == 0:
continue
for root, dirs, files in os.walk("/dev/disk/by-id/"):
global wwn
wwn_id = "wwn-0x%x" % wwn
if wwn_id not in files:
print("The wwn_id of device(%s) will change to 0x%x" %
("/dev/"+filename, wwn))
ret = True
return ret
if __name__ == "__main__":
# exit with "1" if there is at least one disk's wwn_id will change from scsi_id to ata_id
if check_ata_disk():
exit(1)
exit(0)

View File

@ -45,6 +45,7 @@ Source104: net-set-sriov-names
Source105: rule_generator.functions Source105: rule_generator.functions
Source106: write_net_rules Source106: write_net_rules
Source107: detect_virt Source107: detect_virt
Source108: sense_data.py
Patch6001: backport-Revert-sysctl.d-switch-net.ipv4.conf.all.rp_filter-f.patch Patch6001: backport-Revert-sysctl.d-switch-net.ipv4.conf.all.rp_filter-f.patch
Patch6002: backport-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch Patch6002: backport-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch
@ -104,6 +105,7 @@ Patch9054: support-disable-cgroup-controllers-we-don-t-want.patch
Patch9055: bugfix-for-cgroup-Swap-cgroup-v1-deletion-and-migration.patch Patch9055: bugfix-for-cgroup-Swap-cgroup-v1-deletion-and-migration.patch
Patch9056: delete-journal-files-except-system.journal-when-jour.patch Patch9056: delete-journal-files-except-system.journal-when-jour.patch
Patch9057: set-the-cpuset.cpus-mems-of-machine.slice-to-all-by-.patch Patch9057: set-the-cpuset.cpus-mems-of-machine.slice-to-all-by-.patch
Patch9058: add-a-new-switch-to-control-whether-udev-complies-wi.patch
BuildRequires: gcc, gcc-c++ BuildRequires: gcc, gcc-c++
BuildRequires: libcap-devel, libmount-devel, pam-devel, libselinux-devel BuildRequires: libcap-devel, libmount-devel, pam-devel, libselinux-devel
@ -472,6 +474,7 @@ install -m 0644 %{SOURCE13} %{buildroot}%{_sysconfdir}/rc.d/rc.local
ln -s rc.d/rc.local %{buildroot}%{_sysconfdir}/rc.local ln -s rc.d/rc.local %{buildroot}%{_sysconfdir}/rc.local
install -m 0644 %{SOURCE100} %{buildroot}/%{_udevrulesdir}/40-%{vendor}.rules install -m 0644 %{SOURCE100} %{buildroot}/%{_udevrulesdir}/40-%{vendor}.rules
install -m 0500 %{SOURCE108} %{buildroot}/usr/lib/udev
# remove rpath info # remove rpath info
for file in $(find %{buildroot}/ -executable -type f -exec file {} ';' | grep "\<ELF\>" | awk -F ':' '{print $1}') for file in $(find %{buildroot}/ -executable -type f -exec file {} ';' | grep "\<ELF\>" | awk -F ':' '{print $1}')
@ -1305,6 +1308,9 @@ fi
%exclude %dir /usr/lib/kernel/install.d %exclude %dir /usr/lib/kernel/install.d
%exclude %{_unitdir}/usb-gadget.target %exclude %{_unitdir}/usb-gadget.target
%ghost /var/lib/systemd/random-seed %ghost /var/lib/systemd/random-seed
# exclude redundant compilation for python file
%exclude /usr/lib/udev/__pycache__/*
/etc/modules-load.d /etc/modules-load.d
/usr/sbin/udevadm /usr/sbin/udevadm
/usr/share/bash-completion/completions/udevadm /usr/share/bash-completion/completions/udevadm
@ -1372,6 +1378,7 @@ fi
%ifnarch sw_64 riscv64 %ifnarch sw_64 riscv64
/usr/lib/udev/dmi_memory_id /usr/lib/udev/dmi_memory_id
%endif %endif
/usr/lib/udev/sense_data.py
%dir /usr/lib/udev/hwdb.d %dir /usr/lib/udev/hwdb.d
%{_udevhwdbdir}/20-bluetooth-vendor-product.hwdb %{_udevhwdbdir}/20-bluetooth-vendor-product.hwdb
@ -1564,6 +1571,11 @@ fi
%{_libdir}/security/pam_systemd.so %{_libdir}/security/pam_systemd.so
%changelog %changelog
* Thu Aug 17 2023 wangyuhang <wangyuhang27@huawei.com> - 253-4
- add a new switch to control whether udev complies with the new SAT standards
and add sense_data.py to check if the device meets the new SAT standards
fix compilation failure with - O0 option
* Mon Jul 31 2023 huyubiao <huyubiao@huawei.com> - 253-3 * Mon Jul 31 2023 huyubiao <huyubiao@huawei.com> - 253-3
- sync the patch from v249 - sync the patch from v249