From 1dff0914db5a08e948140ade8b8d78f457455638 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Wed, 6 Mar 2024 22:25:56 -0600 Subject: [PATCH 1/7] lsdevinfo: extract location codes more efficiently We can avoid spawning subprocesses by using the 'read' builtin. Signed-off-by: Nathan Lynch --- scripts/lsdevinfo | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/lsdevinfo b/scripts/lsdevinfo index 7a3cba3b..1b9203a1 100755 --- a/scripts/lsdevinfo +++ b/scripts/lsdevinfo @@ -309,7 +309,7 @@ for dev in $($LS -d /proc/device-tree/vdevice/vnic* 2> /dev/null); do parent="vio" # get the physical location - physloc=$(tr -d '\0' < $dev/ibm,loc-code) + IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" uniquetype="adapter/vdevice/IBM,vnic" class="adapter" subclass="vdevice" @@ -330,7 +330,7 @@ for dev in $($LS -d /proc/device-tree/vdevice/l-lan* 2> /dev/null); do parent="vio" # get the physical location - physloc=$(tr -d '\0' < $dev/ibm,loc-code) + IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" uniquetype="adapter/vdevice/IBM,l-lan" class="adapter" subclass="vdevice" @@ -352,7 +352,7 @@ for pci_dev in $($LS -d /proc/device-tree/pci* 2> /dev/null); do parent="pci" # get the physical location - physloc=$(tr -d '\0' < $dev/ibm,loc-code) + IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" type="$($OD -t x2 $dev/vendor-id $dev/device-id | $CUT -f3,5 -d ' ' -s --output-delimiter='' | tr -d '\0')" uniquetype="adapter/pci/$type" @@ -372,7 +372,7 @@ done # Look at every ibmvscsi (Virtual SCSI) device for dev in $($LS -d /proc/device-tree/vdevice/v-scsi* 2> /dev/null) ; do # pull the physical location - physloc=$(tr -d '\0' < $dev/ibm,loc-code) + IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" hostphysloc=$physloc connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/v-scsi@//") @@ -508,7 +508,7 @@ done # Look at every ibmvfc (Virtual FibreChannel) device for dev in $($LS -d /proc/device-tree/vdevice/vfc-client* 2> /dev/null) ; do # pull the physical location - physloc=$(tr -d '\0' < $dev/ibm,loc-code) + IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/vfc-client@//") hostphysloc=$physloc From 30311d90c04673d2f8856f6ecc0a7f0b6f51d671 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Wed, 6 Mar 2024 22:49:24 -0600 Subject: [PATCH 2/7] lsdevinfo: reduce escaping in sed commands Use '!' for the substitution delimiter when manipulating path strings that contain '/'. This will make such code more amenable to mechanical transformations to come. Signed-off-by: Nathan Lynch --- scripts/lsdevinfo | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/lsdevinfo b/scripts/lsdevinfo index 1b9203a1..51c7a9fd 100755 --- a/scripts/lsdevinfo +++ b/scripts/lsdevinfo @@ -304,8 +304,8 @@ show_eth () # Look at every vNIC device for dev in $($LS -d /proc/device-tree/vdevice/vnic* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) - name=$($OFPATHNAME -l $(echo $dev | $SED -e "s/\/proc\/device-tree//") 2> /dev/null) - connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/l-lan@//") + name=$($OFPATHNAME -l $(echo $dev | $SED -e "s!/proc/device-tree!!") 2> /dev/null) + connection=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/l-lan@!!") parent="vio" # get the physical location @@ -325,8 +325,8 @@ done # Look at every ibmveth (Virtual Ethernet) device for dev in $($LS -d /proc/device-tree/vdevice/l-lan* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) - name=$($OFPATHNAME -l $(echo $dev | $SED -e "s/\/proc\/device-tree//") 2> /dev/null) - connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/l-lan@//") + name=$($OFPATHNAME -l $(echo $dev | $SED -e "s!/proc/device-tree!!") 2> /dev/null) + connection=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/l-lan@!!") parent="vio" # get the physical location @@ -347,8 +347,8 @@ done for pci_dev in $($LS -d /proc/device-tree/pci* 2> /dev/null); do for dev in $($LS -d $pci_dev/ethernet* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) - name=$($OFPATHNAME -l $(echo $dev | $SED -e "s/\/proc\/device-tree//") 2> /dev/null) - connection=$(echo $pci_dev | $SED -e "s/\/proc\/device-tree\/pci@//") + name=$($OFPATHNAME -l $(echo $dev | $SED -e "s!/proc/device-tree!!") 2> /dev/null) + connection=$(echo $pci_dev | $SED -e "s!/proc/device-tree/pci@!!") parent="pci" # get the physical location @@ -374,10 +374,10 @@ for dev in $($LS -d /proc/device-tree/vdevice/v-scsi* 2> /dev/null) ; do # pull the physical location IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" hostphysloc=$physloc - connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/v-scsi@//") + connection=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/v-scsi@!!") # find the slot so it can be used in sysfs - slot=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/v-scsi@//") + slot=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/v-scsi@!!") # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host*) ; do @@ -509,11 +509,11 @@ done for dev in $($LS -d /proc/device-tree/vdevice/vfc-client* 2> /dev/null) ; do # pull the physical location IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" - connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/vfc-client@//") + connection=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/vfc-client@!!") hostphysloc=$physloc # find the slot so it can be used in sysfs - slot=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/vfc-client@//") + slot=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/vfc-client@!!") # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host* 2> /dev/null) ; do From 8b69d3b7aa2cea81f2aed1febcc812d64236944c Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Wed, 6 Mar 2024 22:55:00 -0600 Subject: [PATCH 3/7] lsdevinfo: use a variable for device tree path There is no reason to repeatedly spell out "/proc/device-tree". Signed-off-by: Nathan Lynch --- scripts/lsdevinfo | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/scripts/lsdevinfo b/scripts/lsdevinfo index 51c7a9fd..29ec2680 100755 --- a/scripts/lsdevinfo +++ b/scripts/lsdevinfo @@ -36,6 +36,7 @@ TR="/usr/bin/tr" OD="/usr/bin/od" CUT="/usr/bin/cut" PSERIES_PLATFORM=$(dirname $0)/pseries_platform +DT="/proc/device-tree" # Usage statemnet usage() @@ -302,10 +303,10 @@ show_eth () } # Look at every vNIC device -for dev in $($LS -d /proc/device-tree/vdevice/vnic* 2> /dev/null); do +for dev in $($LS -d ${DT}/vdevice/vnic* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) - name=$($OFPATHNAME -l $(echo $dev | $SED -e "s!/proc/device-tree!!") 2> /dev/null) - connection=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/l-lan@!!") + name=$($OFPATHNAME -l $(echo $dev | $SED -e "s!${DT}!!") 2> /dev/null) + connection=$(echo $dev | $SED -e "s!${DT}/vdevice/l-lan@!!") parent="vio" # get the physical location @@ -323,10 +324,10 @@ for dev in $($LS -d /proc/device-tree/vdevice/vnic* 2> /dev/null); do done # Look at every ibmveth (Virtual Ethernet) device -for dev in $($LS -d /proc/device-tree/vdevice/l-lan* 2> /dev/null); do +for dev in $($LS -d ${DT}/vdevice/l-lan* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) - name=$($OFPATHNAME -l $(echo $dev | $SED -e "s!/proc/device-tree!!") 2> /dev/null) - connection=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/l-lan@!!") + name=$($OFPATHNAME -l $(echo $dev | $SED -e "s!${DT}!!") 2> /dev/null) + connection=$(echo $dev | $SED -e "s!${DT}/vdevice/l-lan@!!") parent="vio" # get the physical location @@ -344,11 +345,11 @@ for dev in $($LS -d /proc/device-tree/vdevice/l-lan* 2> /dev/null); do done # Look for PCI ethernet devices -for pci_dev in $($LS -d /proc/device-tree/pci* 2> /dev/null); do +for pci_dev in $($LS -d ${DT}/pci* 2> /dev/null); do for dev in $($LS -d $pci_dev/ethernet* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) - name=$($OFPATHNAME -l $(echo $dev | $SED -e "s!/proc/device-tree!!") 2> /dev/null) - connection=$(echo $pci_dev | $SED -e "s!/proc/device-tree/pci@!!") + name=$($OFPATHNAME -l $(echo $dev | $SED -e "s!${DT}!!") 2> /dev/null) + connection=$(echo $pci_dev | $SED -e "s!${DT}/pci@!!") parent="pci" # get the physical location @@ -370,14 +371,14 @@ done # Look at every ibmvscsi (Virtual SCSI) device -for dev in $($LS -d /proc/device-tree/vdevice/v-scsi* 2> /dev/null) ; do +for dev in $($LS -d ${DT}/vdevice/v-scsi* 2> /dev/null) ; do # pull the physical location IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" hostphysloc=$physloc - connection=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/v-scsi@!!") + connection=$(echo $dev | $SED -e "s!${DT}/vdevice/v-scsi@!!") # find the slot so it can be used in sysfs - slot=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/v-scsi@!!") + slot=$(echo $dev | $SED -e "s!${DT}/vdevice/v-scsi@!!") # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host*) ; do @@ -506,14 +507,14 @@ done # Look at every ibmvfc (Virtual FibreChannel) device -for dev in $($LS -d /proc/device-tree/vdevice/vfc-client* 2> /dev/null) ; do +for dev in $($LS -d ${DT}/vdevice/vfc-client* 2> /dev/null) ; do # pull the physical location IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" - connection=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/vfc-client@!!") + connection=$(echo $dev | $SED -e "s!${DT}/vdevice/vfc-client@!!") hostphysloc=$physloc # find the slot so it can be used in sysfs - slot=$(echo $dev | $SED -e "s!/proc/device-tree/vdevice/vfc-client@!!") + slot=$(echo $dev | $SED -e "s!${DT}/vdevice/vfc-client@!!") # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host* 2> /dev/null) ; do From 549cb80bf435681724fb2673c3344df4fbe3b56f Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Wed, 6 Mar 2024 23:05:01 -0600 Subject: [PATCH 4/7] lsdevinfo: slot == connection for vscsi, vfc The same work is performed to set the "slot" and "connection" variables in the vscsi and vfc loops; eliminate the duplication. Signed-off-by: Nathan Lynch --- scripts/lsdevinfo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/lsdevinfo b/scripts/lsdevinfo index 29ec2680..a2709708 100755 --- a/scripts/lsdevinfo +++ b/scripts/lsdevinfo @@ -378,7 +378,7 @@ for dev in $($LS -d ${DT}/vdevice/v-scsi* 2> /dev/null) ; do connection=$(echo $dev | $SED -e "s!${DT}/vdevice/v-scsi@!!") # find the slot so it can be used in sysfs - slot=$(echo $dev | $SED -e "s!${DT}/vdevice/v-scsi@!!") + slot="$connection" # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host*) ; do @@ -514,7 +514,7 @@ for dev in $($LS -d ${DT}/vdevice/vfc-client* 2> /dev/null) ; do hostphysloc=$physloc # find the slot so it can be used in sysfs - slot=$(echo $dev | $SED -e "s!${DT}/vdevice/vfc-client@!!") + slot="$connection" # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host* 2> /dev/null) ; do From 4865ed2cf216437911bd53ba1ded743eae5ebe57 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Wed, 6 Mar 2024 23:07:44 -0600 Subject: [PATCH 5/7] lsdevinfo: extract OF unit addresses without subprocesses The "connection" variables are just the OF unit addresses (following the "@" in the node name). Use shell parameter expansion to efficiently extract these from variables containing the paths. Signed-off-by: Nathan Lynch --- scripts/lsdevinfo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/lsdevinfo b/scripts/lsdevinfo index a2709708..e984a44c 100755 --- a/scripts/lsdevinfo +++ b/scripts/lsdevinfo @@ -375,7 +375,7 @@ for dev in $($LS -d ${DT}/vdevice/v-scsi* 2> /dev/null) ; do # pull the physical location IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" hostphysloc=$physloc - connection=$(echo $dev | $SED -e "s!${DT}/vdevice/v-scsi@!!") + connection="${dev##*@}" # extract unit address # find the slot so it can be used in sysfs slot="$connection" @@ -510,7 +510,7 @@ done for dev in $($LS -d ${DT}/vdevice/vfc-client* 2> /dev/null) ; do # pull the physical location IFS= read -r -d $'\0' physloc < "$dev/ibm,loc-code" - connection=$(echo $dev | $SED -e "s!${DT}/vdevice/vfc-client@!!") + connection="${dev##*@}" # extract unit address hostphysloc=$physloc # find the slot so it can be used in sysfs From a6c1af793dccad86091a699c88a322c4d46ba9d2 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Wed, 6 Mar 2024 23:23:31 -0600 Subject: [PATCH 6/7] lsdevinfo: remove inefficient uses of cat(1) Using redirection and the read builtin suffices. [root@ltc-zz14-lp1 ~]# strace -q -f -c -e wait4,clone,execve,pipe2 /usr/sbin/lsdevinfo -F name device: name="env2" device: name="host0" device: name="sda" /bin/ls: cannot access '/sys/devices/vio/30000004/host*': No such file or directory device: name="host1" % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 96.98 0.387740 1664 233 110 wait4 2.17 0.008676 70 123 clone 0.70 0.002815 37 75 execve 0.14 0.000567 7 81 pipe2 ------ ----------- ----------- --------- --------- ---------------- 100.00 0.399798 780 512 110 total Signed-off-by: Nathan Lynch --- scripts/lsdevinfo | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/lsdevinfo b/scripts/lsdevinfo index e984a44c..b84dbcab 100755 --- a/scripts/lsdevinfo +++ b/scripts/lsdevinfo @@ -399,7 +399,8 @@ for dev in $($LS -d ${DT}/vdevice/v-scsi* 2> /dev/null) ; do scsihost=$($LS -d $host/scsi_host*/ 2> /dev/null) fi - if [[ $(cat $scsihost/state) == "running" ]] ; then + read scsihost_state < "${scsihost}/state" + if [[ "$scsihost_state" == "running" ]] ; then status=1 else status=0 @@ -456,7 +457,8 @@ for dev in $($LS -d ${DT}/vdevice/v-scsi* 2> /dev/null) ; do type="vdisk" physloc=$hostphysloc"-L"$conn - if [[ $(cat $target/state) == "running" ]] ; then + read target_state < "${target}/state" + if [[ "$target_state" == "running" ]] ; then status=1 else status=0 @@ -535,7 +537,8 @@ for dev in $($LS -d ${DT}/vdevice/vfc-client* 2> /dev/null) ; do scsihost=$($LS -d $host/scsi_host*/ 2> /dev/null) fi - if [[ $(cat $scsihost/state) == "running" ]] ; then + read scsihost_state < "${scsihost}/state" + if [[ "$scsihost_state" == "running" ]] ; then status=1 else status=0 @@ -595,7 +598,8 @@ for dev in $($LS -d ${DT}/vdevice/vfc-client* 2> /dev/null) ; do subclass="fcp" type="disk" - if [[ $(cat $t/$target/state) == "running" ]] ; then + read target_state < "${t}/${target}/state" + if [[ "$target_state" == "running" ]] ; then status=1 else status=0 From 8c0e747944a0651ad985143adb2c7afc481f76a1 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Wed, 6 Mar 2024 23:51:30 -0600 Subject: [PATCH 7/7] lsdevinfo: replace pipeline with globbing in vscsi target loop The pipeline is inefficient (multiple grep invocations) and fragile (excluding names we're not interested in instead of just specifying a name that matches what we want). Replace it with a shell glob into an array. [root@ltc-zz14-lp1 ~]# strace -q -f -c -e wait4,clone,execve,pipe2 lsdevinfo -F name device: name="env2" device: name="host0" device: name="sda" /bin/ls: cannot access '/sys/devices/vio/30000004/host*': No such file or directory device: name="host1" % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 97.15 0.308000 1387 222 106 wait4 2.07 0.006572 56 116 clone 0.66 0.002080 29 70 execve 0.12 0.000384 5 75 pipe2 ------ ----------- ----------- --------- --------- ---------------- 100.00 0.317036 656 483 106 total Signed-off-by: Nathan Lynch --- scripts/lsdevinfo | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/lsdevinfo b/scripts/lsdevinfo index b84dbcab..845655d8 100755 --- a/scripts/lsdevinfo +++ b/scripts/lsdevinfo @@ -442,7 +442,9 @@ for dev in $($LS -d ${DT}/vdevice/v-scsi* 2> /dev/null) ; do # loop through the targets for this host. for t in $($LS -d $host/target* 2> /dev/null); do - target=$(echo $($LS -d $t/$($LS $t | $GREP -v uevent | $GREP -v power | $GREP -v subsystem))) + declare -a target_glob + target_glob=("${t}"/*:*:*:*) # could tighten up w/character class (:digit:) + target="${target_glob[0]}" if [[ ! -d $target/block ]]; then name=$(echo $($LS -d $target/block* 2> /dev/null) | $SED -e "s/.*://") else