Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
localmount not unmounting /home at shutdown
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Other Things Gentoo
View previous topic :: View next topic  
Author Message
mi_unixbird
Tux's lil' helper
Tux's lil' helper


Joined: 24 Jul 2015
Posts: 118

PostPosted: Thu Dec 31, 2015 5:24 am    Post subject: localmount not unmounting /home at shutdown Reply with quote

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
View user's profile Send private message
Syl20
l33t
l33t


Joined: 04 Aug 2005
Posts: 619
Location: France

PostPosted: Thu Dec 31, 2015 9:19 am    Post subject: Re: localmount not unmounting /home at shutdown Reply with quote

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
View user's profile Send private message
khayyam
Watchman
Watchman


Joined: 07 Jun 2012
Posts: 6227
Location: Room 101

PostPosted: Thu Dec 31, 2015 10:57 am    Post subject: Re: localmount not unmounting /home at shutdown Reply with quote

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
View user's profile Send private message
Ant P.
Watchman
Watchman


Joined: 18 Apr 2009
Posts: 6920

PostPosted: Thu Dec 31, 2015 4:13 pm    Post subject: Reply with quote

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
View user's profile Send private message
mi_unixbird
Tux's lil' helper
Tux's lil' helper


Joined: 24 Jul 2015
Posts: 118

PostPosted: Thu Dec 31, 2015 5:31 pm    Post subject: Re: localmount not unmounting /home at shutdown Reply with quote

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
View user's profile Send private message
szatox
Advocate
Advocate


Joined: 27 Aug 2013
Posts: 3149

PostPosted: Thu Dec 31, 2015 6:44 pm    Post subject: Reply with quote

How 'bout using 'umount -lf' for unmounting your stuff?
Back to top
View user's profile Send private message
mi_unixbird
Tux's lil' helper
Tux's lil' helper


Joined: 24 Jul 2015
Posts: 118

PostPosted: Thu Dec 31, 2015 9:10 pm    Post subject: Reply with quote

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
View user's profile Send private message
mi_unixbird
Tux's lil' helper
Tux's lil' helper


Joined: 24 Jul 2015
Posts: 118

PostPosted: Fri Jan 01, 2016 1:44 am    Post subject: Reply with quote

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
View user's profile Send private message
mi_unixbird
Tux's lil' helper
Tux's lil' helper


Joined: 24 Jul 2015
Posts: 118

PostPosted: Fri Jan 01, 2016 9:16 pm    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Other Things Gentoo All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum