Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

scripts/dev-needs: Add script to list device dependencies

This script can be useful for:
- Figuring out the list of modules you need to pack in initrd
- Figuring out the list of drivers you need to modularize for a device
to be fully functional without building in any dependencies.
- Figuring out which drivers to enable first, when porting drivers
between kernels (say, to upstream).
- Plotting graphs of system dependencies, etc.

Usage: dev-needs.sh [-c|-d|-m|-f] [filter options] <list of devices>

This script needs to be run on the target device once it has booted to a
shell.

The script takes as input a list of one or more device directories under
/sys/devices and then lists the probe dependency chain (suppliers and
parents) of these devices. It does a breadth first search of the dependency
chain, so the last entry in the output is close to the root of the
dependency chain.

By default it lists the full path to the devices under /sys/devices.

It also takes an optional modifier flag as the first parameter to change
what information is listed in the output. If the requested information is
not available, the device name is printed.

-c lists the compatible string of the dependencies
-d lists the driver name of the dependencies that have probed
-m lists the module name of the dependencies that have a module
-f list the firmware node path of the dependencies
-g list the dependencies as edges and nodes for graphviz
-t list the dependencies as edges for tsort

The filter options provide a way to filter out some dependencies:
--allow-no-driver By default dependencies that don't have a driver
attached are ignored. This is to avoid following
device links to "class" devices that are created
when the consumer probes (as in, not a probe
dependency). If you want to follow these links
anyway, use this flag.

--exclude-devlinks Don't follow device links when tracking probe
dependencies.

--exclude-parents Don't follow parent devices when tracking probe
dependencies.

Signed-off-by: Saravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20200901224842.1787825-1-saravanak@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Saravana Kannan and committed by
Greg Kroah-Hartman
51fae39b d012a719

+321
+6
MAINTAINERS
··· 4994 4994 F: drivers/base/devcoredump.c 4995 4995 F: include/linux/devcoredump.h 4996 4996 4997 + DEVICE DEPENDENCY HELPER SCRIPT 4998 + M: Saravana Kannan <saravanak@google.com> 4999 + L: linux-kernel@vger.kernel.org 5000 + S: Maintained 5001 + F: scripts/dev-needs.sh 5002 + 4997 5003 DEVICE DIRECT ACCESS (DAX) 4998 5004 M: Dan Williams <dan.j.williams@intel.com> 4999 5005 M: Vishal Verma <vishal.l.verma@intel.com>
+315
scripts/dev-needs.sh
··· 1 + #! /bin/sh 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Copyright (c) 2020, Google LLC. All rights reserved. 4 + # Author: Saravana Kannan <saravanak@google.com> 5 + 6 + function help() { 7 + cat << EOF 8 + Usage: $(basename $0) [-c|-d|-m|-f] [filter options] <list of devices> 9 + 10 + This script needs to be run on the target device once it has booted to a 11 + shell. 12 + 13 + The script takes as input a list of one or more device directories under 14 + /sys/devices and then lists the probe dependency chain (suppliers and 15 + parents) of these devices. It does a breadth first search of the dependency 16 + chain, so the last entry in the output is close to the root of the 17 + dependency chain. 18 + 19 + By default it lists the full path to the devices under /sys/devices. 20 + 21 + It also takes an optional modifier flag as the first parameter to change 22 + what information is listed in the output. If the requested information is 23 + not available, the device name is printed. 24 + 25 + -c lists the compatible string of the dependencies 26 + -d lists the driver name of the dependencies that have probed 27 + -m lists the module name of the dependencies that have a module 28 + -f list the firmware node path of the dependencies 29 + -g list the dependencies as edges and nodes for graphviz 30 + -t list the dependencies as edges for tsort 31 + 32 + The filter options provide a way to filter out some dependencies: 33 + --allow-no-driver By default dependencies that don't have a driver 34 + attached are ignored. This is to avoid following 35 + device links to "class" devices that are created 36 + when the consumer probes (as in, not a probe 37 + dependency). If you want to follow these links 38 + anyway, use this flag. 39 + 40 + --exclude-devlinks Don't follow device links when tracking probe 41 + dependencies. 42 + 43 + --exclude-parents Don't follow parent devices when tracking probe 44 + dependencies. 45 + 46 + EOF 47 + } 48 + 49 + function dev_to_detail() { 50 + local i=0 51 + while [ $i -lt ${#OUT_LIST[@]} ] 52 + do 53 + local C=${OUT_LIST[i]} 54 + local S=${OUT_LIST[i+1]} 55 + local D="'$(detail_chosen $C $S)'" 56 + if [ ! -z "$D" ] 57 + then 58 + # This weirdness is needed to work with toybox when 59 + # using the -t option. 60 + printf '%05u\t%s\n' ${i} "$D" | tr -d \' 61 + fi 62 + i=$((i+2)) 63 + done 64 + } 65 + 66 + function already_seen() { 67 + local i=0 68 + while [ $i -lt ${#OUT_LIST[@]} ] 69 + do 70 + if [ "$1" = "${OUT_LIST[$i]}" ] 71 + then 72 + # if-statement treats 0 (no-error) as true 73 + return 0 74 + fi 75 + i=$(($i+2)) 76 + done 77 + 78 + # if-statement treats 1 (error) as false 79 + return 1 80 + } 81 + 82 + # Return 0 (no-error/true) if parent was added 83 + function add_parent() { 84 + 85 + if [ ${ALLOW_PARENTS} -eq 0 ] 86 + then 87 + return 1 88 + fi 89 + 90 + local CON=$1 91 + # $CON could be a symlink path. So, we need to find the real path and 92 + # then go up one level to find the real parent. 93 + local PARENT=$(realpath $CON/..) 94 + 95 + while [ ! -e ${PARENT}/driver ] 96 + do 97 + if [ "$PARENT" = "/sys/devices" ] 98 + then 99 + return 1 100 + fi 101 + PARENT=$(realpath $PARENT/..) 102 + done 103 + 104 + CONSUMERS+=($PARENT) 105 + OUT_LIST+=(${CON} ${PARENT}) 106 + return 0 107 + } 108 + 109 + # Return 0 (no-error/true) if one or more suppliers were added 110 + function add_suppliers() { 111 + local CON=$1 112 + local RET=1 113 + 114 + if [ ${ALLOW_DEVLINKS} -eq 0 ] 115 + then 116 + return 1 117 + fi 118 + 119 + SUPPLIER_LINKS=$(ls -1d $CON/supplier:* 2>/dev/null) 120 + for SL in $SUPPLIER_LINKS; 121 + do 122 + SYNC_STATE=$(cat $SL/sync_state_only) 123 + 124 + # sync_state_only links are proxy dependencies. 125 + # They can also have cycles. So, don't follow them. 126 + if [ "$SYNC_STATE" != '0' ] 127 + then 128 + continue 129 + fi 130 + 131 + SUPPLIER=$(realpath $SL/supplier) 132 + 133 + if [ ! -e $SUPPLIER/driver -a ${ALLOW_NO_DRIVER} -eq 0 ] 134 + then 135 + continue 136 + fi 137 + 138 + CONSUMERS+=($SUPPLIER) 139 + OUT_LIST+=(${CON} ${SUPPLIER}) 140 + RET=0 141 + done 142 + 143 + return $RET 144 + } 145 + 146 + function detail_compat() { 147 + f=$1/of_node/compatible 148 + if [ -e $f ] 149 + then 150 + echo -n $(cat $f) 151 + else 152 + echo -n $1 153 + fi 154 + } 155 + 156 + function detail_module() { 157 + f=$1/driver/module 158 + if [ -e $f ] 159 + then 160 + echo -n $(basename $(realpath $f)) 161 + else 162 + echo -n $1 163 + fi 164 + } 165 + 166 + function detail_driver() { 167 + f=$1/driver 168 + if [ -e $f ] 169 + then 170 + echo -n $(basename $(realpath $f)) 171 + else 172 + echo -n $1 173 + fi 174 + } 175 + 176 + function detail_fwnode() { 177 + f=$1/firmware_node 178 + if [ ! -e $f ] 179 + then 180 + f=$1/of_node 181 + fi 182 + 183 + if [ -e $f ] 184 + then 185 + echo -n $(realpath $f) 186 + else 187 + echo -n $1 188 + fi 189 + } 190 + 191 + function detail_graphviz() { 192 + if [ "$2" != "ROOT" ] 193 + then 194 + echo -n "\"$(basename $2)\"->\"$(basename $1)\"" 195 + else 196 + echo -n "\"$(basename $1)\"" 197 + fi 198 + } 199 + 200 + function detail_tsort() { 201 + echo -n "\"$2\" \"$1\"" 202 + } 203 + 204 + function detail_device() { echo -n $1; } 205 + 206 + alias detail=detail_device 207 + ALLOW_NO_DRIVER=0 208 + ALLOW_DEVLINKS=1 209 + ALLOW_PARENTS=1 210 + 211 + while [ $# -gt 0 ] 212 + do 213 + ARG=$1 214 + case $ARG in 215 + --help) 216 + help 217 + exit 0 218 + ;; 219 + -c) 220 + alias detail=detail_compat 221 + ;; 222 + -m) 223 + alias detail=detail_module 224 + ;; 225 + -d) 226 + alias detail=detail_driver 227 + ;; 228 + -f) 229 + alias detail=detail_fwnode 230 + ;; 231 + -g) 232 + alias detail=detail_graphviz 233 + ;; 234 + -t) 235 + alias detail=detail_tsort 236 + ;; 237 + --allow-no-driver) 238 + ALLOW_NO_DRIVER=1 239 + ;; 240 + --exclude-devlinks) 241 + ALLOW_DEVLINKS=0 242 + ;; 243 + --exclude-parents) 244 + ALLOW_PARENTS=0 245 + ;; 246 + *) 247 + # Stop at the first argument that's not an option. 248 + break 249 + ;; 250 + esac 251 + shift 252 + done 253 + 254 + function detail_chosen() { 255 + detail $1 $2 256 + } 257 + 258 + if [ $# -eq 0 ] 259 + then 260 + help 261 + exit 1 262 + fi 263 + 264 + CONSUMERS=($@) 265 + OUT_LIST=() 266 + 267 + # Do a breadth first, non-recursive tracking of suppliers. The parent is also 268 + # considered a "supplier" as a device can't probe without its parent. 269 + i=0 270 + while [ $i -lt ${#CONSUMERS[@]} ] 271 + do 272 + CONSUMER=$(realpath ${CONSUMERS[$i]}) 273 + i=$(($i+1)) 274 + 275 + if already_seen ${CONSUMER} 276 + then 277 + continue 278 + fi 279 + 280 + # If this is not a device with a driver, we don't care about its 281 + # suppliers. 282 + if [ ! -e ${CONSUMER}/driver -a ${ALLOW_NO_DRIVER} -eq 0 ] 283 + then 284 + continue 285 + fi 286 + 287 + ROOT=1 288 + 289 + # Add suppliers to CONSUMERS list and output the consumer details. 290 + # 291 + # We don't need to worry about a cycle in the dependency chain causing 292 + # infinite loops. That's because the kernel doesn't allow cycles in 293 + # device links unless it's a sync_state_only device link. And we ignore 294 + # sync_state_only device links inside add_suppliers. 295 + if add_suppliers ${CONSUMER} 296 + then 297 + ROOT=0 298 + fi 299 + 300 + if add_parent ${CONSUMER} 301 + then 302 + ROOT=0 303 + fi 304 + 305 + if [ $ROOT -eq 1 ] 306 + then 307 + OUT_LIST+=(${CONSUMER} "ROOT") 308 + fi 309 + done 310 + 311 + # Can NOT combine sort and uniq using sort -suk2 because stable sort in toybox 312 + # isn't really stable. 313 + dev_to_detail | sort -k2 -k1 | uniq -f 1 | sort | cut -f2- 314 + 315 + exit 0