Skip to content

Commit dd9299f

Browse files
author
Eric Wheeler
committed
Recurse block device stacking hierarchies
Turn LEDs on or off depending on their existence at the bottom of in block device stacks. This works with pretty much any hierarchy (RAID, LVM, DM, etc) because the kernel tracks block device stacking dependencies in /sys/block/<dev>/slaves/* (which can be seen as a tree using the tool `lsblk`). For example: ] grep md9 /proc/mdstat md9 : active raid5 sdg[0] sde[6] sdj[4] sdk[3] sdf[2] sdl[1] ] encled md9 0:0:18:0/Slot11 sde fault_off locate_off 0:0:18:0/Slot08 sdf fault_off locate_off 0:0:18:0/Slot06 sdg fault_off locate_off 0:0:18:0/Slot10 sdj fault_off locate_off 0:0:18:0/Slot09 sdk fault_off locate_off 0:0:18:0/Slot07 sdl fault_off locate_off ] encled md9 locate ] encled md9 0:0:18:0/Slot11 sde fault_off LOCATE_ON 0:0:18:0/Slot08 sdf fault_off LOCATE_ON 0:0:18:0/Slot06 sdg fault_off LOCATE_ON 0:0:18:0/Slot10 sdj fault_off LOCATE_ON 0:0:18:0/Slot09 sdk fault_off LOCATE_ON 0:0:18:0/Slot07 sdl fault_off LOCATE_ON In the more complex stack shown below, /dev/bcache0 is backed by /dev/md125 and /dev/md126. Now encled can find the referenced devices at any point in the stack: ] encled md125 0:0:18:0/Slot03 sdh fault_off locate_off 0:0:18:0/Slot02 sdc fault_off locate_off ] encled md126 0:0:18:0/Slot01 sdb fault_off locate_off 0:0:18:0/Slot00 sdi fault_off locate_off ] encled bcache0 0:0:18:0/Slot03 sdh fault_off locate_off 0:0:18:0/Slot01 sdb fault_off locate_off 0:0:18:0/Slot02 sdc fault_off locate_off 0:0:18:0/Slot00 sdi fault_off locate_off Signed-off-by: Eric Wheeler <[email protected]>
1 parent 60fd6c7 commit dd9299f

File tree

1 file changed

+60
-18
lines changed

1 file changed

+60
-18
lines changed

encled

+60-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env python3
22
import os
33
import sys
4+
import re
45

56
HELP = """
67
@@ -30,6 +31,13 @@ HELP = """
3031
encled sda locate - enable 'locate' for slot with sda block device
3132
encled /dev/sdbz fault - enable fault indicator slot with sdbz block device
3233
34+
Recurse block device stacking hierarchies:
35+
encled bcache0 locate - locate all disks used by /dev/bcache0
36+
encled md0 - list all disks that are RAID members of /dev/md0
37+
encled /dev/vg0/lv - list all disks that back the logical volume 'vg0/lv'
38+
encled /dev/vg0/lv - list all disks that back the logical volume 'vg0/lv'
39+
encled /dev/mapper/myluks - list all disks that back an encrypted volume
40+
3341
"""
3442

3543
CLASS = '/sys/class/enclosure/'
@@ -153,6 +161,38 @@ def list_all():
153161
devlist.append((e, s, path, status))
154162
return devlist
155163

164+
# Recursively find SCSI devices in block device stacking hierarchies
165+
# by referencing /sys/block/<dev>/slaves/*
166+
def find_parent_devs(dev_names):
167+
global depth
168+
169+
new_names = []
170+
for dev_path in dev_names:
171+
# Read symlinks, like from /dev/mapper/foo:
172+
if os.path.islink(dev_path):
173+
dev_path = os.readlink(dev_path)
174+
175+
# Use basename, we only need the name not the path:
176+
dev_name = os.path.basename(dev_path)
177+
178+
# Strip partition numbers:
179+
dev_name = re.sub('^(sd[a-z]+)\d*$', lambda x: x.group(1), dev_name)
180+
181+
slave_path = '/sys/block/' + dev_name + '/slaves/'
182+
if re.match('^sd[a-z]+$', dev_name):
183+
new_names.append(dev_name)
184+
elif os.path.exists(slave_path):
185+
new_names += find_parent_devs(os.listdir(slave_path))
186+
187+
dev_names += new_names
188+
189+
# Only return SCSI devices:
190+
sd = []
191+
for dev in dev_names:
192+
if re.match('^sd[a-z]+$', dev):
193+
sd.append(dev)
194+
195+
return set(sd)
156196

157197
def main(argv):
158198
if len(argv) > 1 and argv[1] in ('--help', '-h', '-help', '/?', '?', 'help', '-v', '--version', '-V'):
@@ -164,6 +204,7 @@ def main(argv):
164204
return(-1)
165205

166206
devlist = list_all()
207+
devs = []
167208
if len(argv) < 2:
168209
if not devlist:
169210
print ("No enclosure devices found")
@@ -190,29 +231,30 @@ def main(argv):
190231
if result: return(result)
191232
return(0)
192233

193-
if 'sd' in argv[1] or '/dev' in argv[1]:
194-
name = argv[1].lower().split('/')[-1]
195-
for d in devlist:
196-
if(d[3][0] == name):
197-
dev = d
198-
break
199-
else:
200-
print(f"encled: Unable to find device {name} in enclosure slots. (note: on-board SATA ports are not supported)")
201-
return(-1)
202-
203-
elif '/' in argv[1]:
234+
if re.match('^\d+:\d+:\d+:\d+/Slot\d+$', argv[1]):
204235
(enc, slot) = argv[1].split('/')
205236
path = find_name(enc, slot)
206237
dev = (enc, slot, path, get_status(path))
238+
devs.append(dev)
239+
if not len(devs):
240+
print ("encled: Incorrect enclosure/slot or device syntax")
241+
print (HELP)
242+
return(-1)
207243
else:
208-
print ("encled: Incorrect enclosure/slot or device syntax")
209-
print (HELP)
210-
return(-1)
244+
names = find_parent_devs([ argv[1] ])
245+
for d in devlist:
246+
if(d[3][0] in names):
247+
devs.append(d)
248+
if not len(devs):
249+
print(f"encled: Unable to find device {argv[1]} in enclosure slots. (note: on-board SATA ports are not supported)")
250+
return(-1)
211251

212-
if len(argv) < 3:
213-
print_status(dev[0], dev[1], dev[3])
214-
else:
215-
set_status(dev[2], argv[2])
252+
253+
for dev in devs:
254+
if len(argv) < 3:
255+
print_status(dev[0], dev[1], dev[3])
256+
else:
257+
set_status(dev[2], argv[2])
216258

217259

218260
if __name__ == '__main__':

0 commit comments

Comments
 (0)