]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/xfs_scrub_all.in
3 # Run online scrubbers in parallel, but avoid thrashing.
5 # Copyright (C) 2018 Oracle. All rights reserved.
7 # Author: Darrick J. Wong <darrick.wong@oracle.com>
9 # This program is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU General Public License
11 # as published by the Free Software Foundation; either version 2
12 # of the License, or (at your option) any later version.
14 # This program is distributed in the hope that it would be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write the Free Software Foundation,
21 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
34 '''Return /dev/null in subprocess writable format.'''
36 from subprocess
import DEVNULL
39 return open(os
.devnull
, 'wb')
42 '''Map mountpoints to physical disks.'''
45 cmd
=['lsblk', '-o', 'KNAME,TYPE,FSTYPE,MOUNTPOINT', '-J']
46 result
= subprocess
.Popen(cmd
, stdout
=subprocess
.PIPE
)
48 if result
.returncode
!= 0:
50 sarray
= [x
.decode('utf-8') for x
in result
.stdout
.readlines()]
51 output
= ' '.join(sarray
)
52 bdevdata
= json
.loads(output
)
53 # The lsblk output had better be in disks-then-partitions order
54 for bdev
in bdevdata
['blockdevices']:
55 if bdev
['type'] in ('disk', 'loop'):
56 lastdisk
= bdev
['kname']
57 if bdev
['fstype'] == 'xfs':
58 mnt
= bdev
['mountpoint']
64 fs
[mnt
] = set([lastdisk
])
67 def kill_systemd(unit
, proc
):
68 '''Kill systemd unit.'''
70 cmd
=['systemctl', 'stop', unit
]
71 x
= subprocess
.Popen(cmd
)
74 def run_killable(cmd
, stdout
, killfuncs
, kill_fn
):
75 '''Run a killable program. Returns program retcode or -1 if we can't start it.'''
77 proc
= subprocess
.Popen(cmd
, stdout
= stdout
)
78 real_kill_fn
= lambda: kill_fn(proc
)
79 killfuncs
.add(real_kill_fn
)
82 killfuncs
.remove(real_kill_fn
)
85 return proc
.returncode
89 def run_scrub(mnt
, cond
, running_devs
, mntdevs
, killfuncs
):
90 '''Run a scrub process.'''
91 global retcode
, terminate
93 print("Scrubbing %s..." % mnt
)
100 # Try it the systemd way
101 cmd
=['systemctl', 'start', 'xfs_scrub@%s' % mnt
]
102 ret
= run_killable(cmd
, DEVNULL(), killfuncs
, \
103 lambda proc
: kill_systemd('xfs_scrub@%s' % mnt
, proc
))
104 if ret
== 0 or ret
== 1:
105 print("Scrubbing %s done, (err=%d)" % (mnt
, ret
))
113 # Invoke xfs_scrub manually
114 cmd
=['@sbindir@/xfs_scrub', '@scrub_args@', mnt
]
115 ret
= run_killable(cmd
, None, killfuncs
, \
116 lambda proc
: proc
.terminate())
118 print("Scrubbing %s done, (err=%d)" % (mnt
, ret
))
126 print("Unable to start scrub tool.")
129 running_devs
-= mntdevs
135 '''Find mounts, schedule scrub runs.'''
137 a
= (mnt
, cond
, running_devs
, devs
, killfuncs
)
138 thr
= threading
.Thread(target
= run_scrub
, args
= a
)
140 global retcode
, terminate
144 # Tail the journal if we ourselves aren't a service...
146 if 'SERVICE_MODE' not in os
.environ
:
148 cmd
=['journalctl', '--no-pager', '-q', '-S', 'now', \
149 '-f', '-u', 'xfs_scrub@*', '-o', \
151 journalthread
= subprocess
.Popen(cmd
)
155 # Schedule scrub jobs...
158 cond
= threading
.Condition()
160 if len(running_devs
) == 0:
161 mnt
, devs
= fs
.popitem()
162 running_devs
.update(devs
)
169 if dev
in running_devs
:
173 running_devs
.update(devs
)
181 except KeyboardInterrupt:
183 print("Terminating...")
185 while len(killfuncs
) > 0:
191 if journalthread
is not None:
192 journalthread
.terminate()
194 # See the service mode comments in xfs_scrub.c for why we do this.
195 if 'SERVICE_MODE' in os
.environ
:
202 if __name__
== '__main__':