Fuse mounts, Ctlr+C and SIGKILL

97 views
Skip to first unread message

Anatol Pomozov

unread,
May 7, 2011, 9:03:37 PM5/7/11
to tup-...@googlegroups.com
Hi,

There are some thought how to make fuse-based tup more friendly to users.

Quite often I try to kill tup by Ctrl+C and accidentally press Ctlr+C
twice. This calls immediate exit(). Such exit as well as SIGKILL leave
fuse mount directory in a broken state. I think that immediate exit
should not be used for double Ctrl+C. Here is my idea how it should
look like instead:

* Ctrl+C stops executing new commands, and waiting for the running
children processes. It is the same as tup works now.
* double Ctrl+C - force stop. It should kill all children, but perform
correct shutdown (save database, unmount fuse). The tup shutdown is
pretty fast anyway.
* SIGKILL. We cannot do anything here - the app is killed by OS and it
leaves the fuse mount point in a broken state. I suggest that tup
should recover the mount point next time it starts. Tup should check
.tup/mnt before fuse_mount() and if it says "Device is busy" then run
"fusemount -u .tup/mnt" internally. Even more - sometimes the only way
for me to unmount the invalid fuse mount is to run "sudo umount -l
.tup/mnt". So if "fusemount -u" does not work - it should show a
useful message, something like "Please run 'sudo umount -l .tup/mnt'
to fix the problem".

What do you think?

Mike Shal

unread,
May 7, 2011, 11:44:05 PM5/7/11
to tup-...@googlegroups.com
On Sat, May 7, 2011 at 9:03 PM, Anatol Pomozov <anatol....@gmail.com> wrote:
> Hi,
>
> There are some thought how to make fuse-based tup more friendly to users.
>
> Quite often I try to kill tup by Ctrl+C and accidentally press Ctlr+C
> twice. This calls immediate exit(). Such exit as well as SIGKILL leave
> fuse mount directory in a broken state. I think that immediate exit
> should not be used for double Ctrl+C. Here is my idea how it should
> look like instead:
>
> * Ctrl+C stops executing new commands, and waiting for the running
> children processes. It is the same as tup works now.
> * double Ctrl+C - force stop. It should kill all children, but perform
> correct shutdown (save database, unmount fuse). The tup shutdown is
> pretty fast anyway.

I was considering combining these two and just have a single ctrl-C
that immediately shuts down all child processes. This couldn't be done
(easily) before since a child process may have written a file before
we got the notification, since the notification went through a socket
with ldpreload. In the fuse branch it is all in the same process, so
it should be easier to just shut down the process and remove all the
files it created.

> * SIGKILL. We cannot do anything here - the app is killed by OS and it
> leaves the fuse mount point in a broken state. I suggest that tup
> should recover the mount point next time it starts. Tup should check
> .tup/mnt before fuse_mount() and if it says "Device is busy" then run
> "fusemount -u .tup/mnt" internally. Even more - sometimes the only way
> for me to unmount the invalid fuse mount is to run "sudo umount -l
> .tup/mnt". So if "fusemount -u" does not work - it should show a
> useful message, something like "Please run 'sudo umount -l .tup/mnt'
> to fix the problem".

This makes sense to me. By "it says 'device is busy'" do you mean we
would get an errno set to that value? Or how would we know?

-Mike

Anatol Pomozov

unread,
May 7, 2011, 11:55:02 PM5/7/11
to tup-...@googlegroups.com
On Sat, May 7, 2011 at 8:44 PM, Mike Shal <mar...@gmail.com> wrote:
> On Sat, May 7, 2011 at 9:03 PM, Anatol Pomozov <anatol....@gmail.com> wrote:
>> Hi,
>>
>> There are some thought how to make fuse-based tup more friendly to users.
>>
>> Quite often I try to kill tup by Ctrl+C and accidentally press Ctlr+C
>> twice. This calls immediate exit(). Such exit as well as SIGKILL leave
>> fuse mount directory in a broken state. I think that immediate exit
>> should not be used for double Ctrl+C. Here is my idea how it should
>> look like instead:
>>
>> * Ctrl+C stops executing new commands, and waiting for the running
>> children processes. It is the same as tup works now.
>> * double Ctrl+C - force stop. It should kill all children, but perform
>> correct shutdown (save database, unmount fuse). The tup shutdown is
>> pretty fast anyway.
>
> I was considering combining these two and just have a single ctrl-C
> that immediately shuts down all child processes.
> This couldn't be done

Sounds good to me.

> (easily) before since a child process may have written a file before
> we got the notification, since the notification went through a socket
> with ldpreload. In the fuse branch it is all in the same process, so
> it should be easier to just shut down the process and remove all the
> files it created.
>
>> * SIGKILL. We cannot do anything here - the app is killed by OS and it
>> leaves the fuse mount point in a broken state. I suggest that tup
>> should recover the mount point next time it starts. Tup should check
>> .tup/mnt before fuse_mount() and if it says "Device is busy" then run
>> "fusemount -u .tup/mnt" internally. Even more - sometimes the only way
>> for me to unmount the invalid fuse mount is to run "sudo umount -l
>> .tup/mnt". So if "fusemount -u" does not work - it should show a
>> useful message, something like "Please run 'sudo umount -l .tup/mnt'
>> to fix the problem".
>
> This makes sense to me. By "it says 'device is busy'" do you mean we
> would get an errno set to that value? Or how would we know?

This message I see when I try to mount failed directory. I think it
comes from mount() syscall.

I do not know how stat() behaves in such case (I can try some time
later). Or we can check fuse_mount() return value. It returns NULL on
failure. Failure usually means that the dir is already mounted so we
can do something like:

ret = fuse_mount()
if (!ret) {
// Let's unmount it
system("fusemount -u .tup/mnt");
// retry mount
ret = fuse_mount();
if (!ret) {
// OK, fail for real
printf(stderr, "Please unmount with 'sudo umount -l .tup/mnt'");
return -1;
}
}

Anatol Pomozov

unread,
May 13, 2011, 6:34:10 PM5/13/11
to tup-...@googlegroups.com
Hi

>> This makes sense to me. By "it says 'device is busy'" do you mean we
>> would get an errno set to that value? Or how would we know?
>
> This message I see when I try to mount failed directory. I think it
> comes from mount() syscall.
>
> I do not know how stat() behaves in such case (I can try some time
> later). Or we can check fuse_mount() return value. It returns NULL on
> failure. Failure usually means that the dir is already mounted so we
> can do something like:
>
> ret = fuse_mount()
> if (!ret) {
>  // Let's unmount it
>  system("fusemount -u .tup/mnt");
>  // retry mount
>  ret = fuse_mount();
>  if (!ret) {
>    // OK, fail for real
>    printf(stderr, "Please unmount with 'sudo umount -l .tup/mnt'");
>    return -1;
>  }
> }
>

Here is the change that does what I was talking about
https://github.com/anatol/tup/commits/fuse-autounmount

Please test it by
1) Run long-running "tup upd"
2) killall -9 tup
3) check that .tup/mnt is mounted by "ls .tup/mnt"
4) Run "tup upd" again

On Macosx the patch works great. On Ubuntu 10.04 umount() requires
superuser permissions (I do not know why), so I just show a message
"Run sudo umount -l .tup/mnt"

Mike Shal

unread,
May 14, 2011, 10:54:06 AM5/14/11
to tup-...@googlegroups.com

It's merged - thanks! Though I had to remove the rmdir() on .tup/mnt,
since it would kill the monitor process. This directory would have
been created as part of 'tup init' if tup used fuse from the
beginning, but I don't have an easy way to upgrade the files in the
.tup/ directory after someone runs 'tup init'. So what I do if I need
a new file in the .tup directory is just always try to create it, and
if it already exists then don't report an error.

-Mike

Reply all
Reply to author
Forward
0 new messages