View previous topic :: View next topic |
Author |
Message |
mi_unixbird Tux's lil' helper
Joined: 24 Jul 2015 Posts: 118
|
Posted: Thu Dec 31, 2015 5:24 am Post subject: localmount not unmounting /home at shutdown |
|
|
Okay, my actual case is more complex than the title suggests and I can in fact solve it but the solution is not elegant, so here's the deal:
I run a script that monitors my battery levels of my notebook and does stuff at low battery. This script is written in bash and contains a "sleep" command, it is daemonized with start-stop-daemon which means that when the daemon exits the sleep process actually survives the kill.
This sleep command has a cwd of my $HOME
Because the sleep interval is 2 minutes. localmount on shutdown refuses to unmount /home for a full two minutes because it sees a process still has a cwd of $HOME inside /home, at least, I'm 99% sure this is what is going on since manually killing the sleep will make the shutdown proceed normally.
Now here's where it gets unorthodox and I realize that what I am doing is unsupported but I use Runit in conjunction with OpenRC. My pid1 is /sbin/runit rather than sysvinit. This is my `/etc/runit/3` or the file that gets called when Runit shuts down:
Code: | #!/bin/bash
. /etc/runit/output
exec >/dev/console 2>&1
export PATH=/sbin:/usr/sbin:/bin:/usr/bin
announce "Waiting for services to stop"
sv force-stop /var/service/*
sv exit /var/service/*
success "stopped"
announce "unlinking /var/service"
unlink /var/service &&
success "unlinked"
#announce "Sending TERM signal to processes"
#pkill --inverse -s0,1 -TERM
#sleep 1
#announce "Sending KILL signal to processes"
#pkill --inverse -s0,1 -KILL
if [[ -x /etc/runit/reboot ]] ; then
announce "telling OpenRC to reboot"
rc reboot
else
announce "telling OpenRC to shut down"
rc shutdown
fi |
The commented code if I uncomment it will just fix it easily. It will just kill all the things before telling OpenRC to shutdown/reboot which seems like a hack to me. Furthermore there is duplicated functionality as it kills many of the processes that OpenRC is supposed to kill, the latter then gives me warnings.
So basically, is there a way to patch localmount to ensure that it'll kill anything that is needed to unmount or unmount in a lazy way if possible. I looked at the code for /etc/init.d/localmount and I must admit that I don't understand a lot of it, it seems to use a lot of openrc-run stuff:
Code: | # Now everything else, except network filesystems as the
# network should be down by this point.
einfo "Unmounting filesystems"
eindent
local fs=
for x in $net_fs_list $extra_net_fs_list; do
fs="$fs${fs:+|}$x"
done
[ -n "$fs" ] && fs="^($fs)$"
do_unmount umount --skip-point-regex "$no_umounts_r" \
"${fs:+--skip-fstype-regex}" $fs --nonetdev
eoutdent
|
That seems to be the relevant part though, but I'not sure how "do_unmount" works and what it does. _________________ execctl --path exec filectl --current-directory list |
|
Back to top |
|
|
Syl20 l33t
Joined: 04 Aug 2005 Posts: 619 Location: France
|
Posted: Thu Dec 31, 2015 9:19 am Post subject: Re: localmount not unmounting /home at shutdown |
|
|
mi_unixbird wrote: | This sleep command has a cwd of my $HOME |
Is changing the current directory before the sleep command out of question ? That's an easy way to resolve your problem. |
|
Back to top |
|
|
khayyam Watchman
Joined: 07 Jun 2012 Posts: 6227 Location: Room 101
|
Posted: Thu Dec 31, 2015 10:57 am Post subject: Re: localmount not unmounting /home at shutdown |
|
|
mi_unixbird ...
A couple of observations ...
Firstly, as this script is 'ac_adapter' plugged/unplugged related then why not run from acpid? This way its entirely outside of the user account, and will be handled by 'rc shutdown'.
Secondly, rather than a 'sleep 120' you should just run the task from cron, and exit.
Thirdly, its possible there exists something that provides the same functionality, ie, app-laptop/laptop-mode-tools.
best ... khay |
|
Back to top |
|
|
Ant P. Watchman
Joined: 18 Apr 2009 Posts: 6920
|
Posted: Thu Dec 31, 2015 4:13 pm Post subject: |
|
|
You're already using runit; just make that script a runit service too.
If you don't want to go that far, `fuser -km /home` in /etc/runit/3 would be safer than pkill. |
|
Back to top |
|
|
mi_unixbird Tux's lil' helper
Joined: 24 Jul 2015 Posts: 118
|
Posted: Thu Dec 31, 2015 5:31 pm Post subject: Re: localmount not unmounting /home at shutdown |
|
|
CneGroumF wrote: | mi_unixbird wrote: | This sleep command has a cwd of my $HOME |
Is changing the current directory before the sleep command out of question ? That's an easy way to resolve your problem. |
It is, there are many ways to stop it, but I don't think it should be possible for a non root user to delay the shutdown by 2 minutes. So I seek to solve this problem in a different way.
To answer all the other things about running the script differently: All those options aren't possible because there needs to be running an instance of this script per X session as it hooks onto my conky and changes my wallpaper to bright red when the battery is about to die. And again, I do not want it to be possible at all that a non root user's setup can delay the shutdown process by 2 minutes.
"fuser -km /home" seems like a real solution but I want this to be part of localmount's stop script.
Basically, I consider it a bug that localmount does not kill any processes that are accessing the resources it tries to unmount. At least in my implementation, I'm not sure if the normal Gentoo shutdown process does have a way of first killing all that.
Anyway, I found the "do_unmount" function in /lib64/sh/rc-mount.sh, maybe that will provide some insights. _________________ execctl --path exec filectl --current-directory list |
|
Back to top |
|
|
szatox Advocate
Joined: 27 Aug 2013 Posts: 3149
|
Posted: Thu Dec 31, 2015 6:44 pm Post subject: |
|
|
How 'bout using 'umount -lf' for unmounting your stuff? |
|
Back to top |
|
|
mi_unixbird Tux's lil' helper
Joined: 24 Jul 2015 Posts: 118
|
Posted: Thu Dec 31, 2015 9:10 pm Post subject: |
|
|
szatox wrote: | How 'bout using 'umount -lf' for unmounting your stuff? |
Tried to patch that into the stop() section of localmount, that created a loooot of errors during shutdown.
But anyway, my current solution involves this inside of 3:
Code: | users=$(get_members users)
attempt "Sending TERM signal to all remaining user processes"
retcode=0
for user in $users; do
pkill -TERM -u $user ||
retcode=$?
done
end $retcode
sleep 1
attempt "Sending KILL signal to all remaining user processes"
retcode=0
for user in $users; do
pkill -KILL -u $user ||
retcode=$?
done
end $retcode |
It basically sends a term signal to every process owned by every process in the "users" group and a kill signal after that, that seems to work. _________________ execctl --path exec filectl --current-directory list |
|
Back to top |
|
|
mi_unixbird Tux's lil' helper
Joined: 24 Jul 2015 Posts: 118
|
Posted: Fri Jan 01, 2016 1:44 am Post subject: |
|
|
My current solution to this problem involves this script into the boot runlevel:
Code: | #!/sbin/openrc-run
# Released into the public domain
description="shim that when started does nothing but when stopped kills all processes of users belonging in the users group"
depend()
{
after localmount
}
start () {
return 0
}
stop()
{
local users=$(awk -F':' "/^users/{print \$4}" /etc/group | tr ',', '\n')
einfo "Sending a TERM signal to processes in the users group"
local user
for user in $users; do
pkill -TERM -u $user
done
eindent
ebegin "Waiting $killuserprocs_delay seconds for all processes to die"
local now=$(date +%s)
local timeout=$((now+$killuserprocs_delay))
for user in $users; do
while ps -U $user &>/dev/null; do
if [[ $(date +%s) -gt timeout ]]; then
local remaining=true
break
fi
done
done
local remaining=${remaining-false}
if $remaining; then
eend 1 "Processes remaining"
einfo "Sending KILL signal to all remaining user processes"
for user in $users; do
pkill -KILL -u $user
done
else
eend 0
fi
eoutdent
return 0
} |
Which feels more elegant as it's now moved inside OpenRC but it still feels like a hack to have a "service" that is only stopped and not started. Is there any cleaner way execute some commands with OpenRC when shutdown or reboot is issued? _________________ execctl --path exec filectl --current-directory list |
|
Back to top |
|
|
mi_unixbird Tux's lil' helper
Joined: 24 Jul 2015 Posts: 118
|
Posted: Fri Jan 01, 2016 9:16 pm Post subject: |
|
|
So in my quest to optimize this shutdown I change /etc/init.d/killprocs to this:
Code: | description="Kill all processes so we can unmount disks cleanly."
patience=${patience-5}
depend()
{
keyword -prefix
}
start()
{
einfo "Sending TERM signal to remaining processes"
killall5 -15 ${killall5_opts}
eindent
ebegin "Waiting $patience seconds for processes to die"
now=$(date +%s)
timeout=$((now+$patience))
session=$(ps -p $$ -o sid=)
while true ; do
remaining_pids=( $(ps -A -o sid=,pid= | egrep -v "^\s*(0|1|$session)" | awk '{print $2}') )
remaining_count=${#remaining_pids[@]}
if [[ $remaining_count = 0 || $(date +%s) -gt timeout ]]; then
break
fi
done
if [[ $remaining_count -gt 0 ]]; then
ewend 1 "$remaining_count Processes remaining"
info "Sending KILL signal to remaining processes"
killall5 -9 ${killall5_opts}
else
eend 0
fi
eoutdent
return 0
}
|
Basically, the differences betweenthe supplied version and this one is that the supplied version waits 1 second before issuing the KILL Signal flat. Which means that processes that take more than 1 second are killed and if none take longer than 1 second to gracefully die the system unecessarily locks up for a second.
This version waits however long it takes for all those processes to actually die, by default 5 seconds but if all die within a thousandth of a second it waits that long. Not sure if there isanything wrong with my impementation or if there are caveats but it seems to work at least. It just checks if any processes who do not have session id 0 (kernel threads), 1 or the session of the script itself are still alive in a loop. As far as I understand killall5 it sends signals to any process that does not meet the above criteria. _________________ execctl --path exec filectl --current-directory list |
|
Back to top |
|
|
|