From ebcccbd3581d34d7fefb975c0255a39a3e39e122 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 19 Jul 2006 16:49:59 +0000 Subject: [PATCH] * Added a tool to find additional roots for the garbage collector, such as open files, current directories, mmaped files, etc. This is inherently unportable, but it's easy to adapt this script to other platforms. Currently we call `lsof' and try to read various bits in /proc/NNN. The goal is to prevent the garbage collector from removing store paths that are no longer reachable from a permanent root but that are still in use (for instance, after the user has done "nix-env -e" on a running program). --- scripts/Makefile.am | 6 ++-- scripts/find-runtime-roots.pl.in | 58 ++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 scripts/find-runtime-roots.pl.in diff --git a/scripts/Makefile.am b/scripts/Makefile.am index bffbdbde5..7b0aef061 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -7,13 +7,14 @@ noinst_SCRIPTS = nix-profile.sh generate-patches.pl nix-pull nix-push: readmanifest.pm readconfig.pm download-using-manifests.pl -install-exec-local: readmanifest.pm download-using-manifests.pl +install-exec-local: readmanifest.pm download-using-manifests.pl find-runtime-roots.pl $(INSTALL) -d $(DESTDIR)$(sysconfdir)/profile.d $(INSTALL_PROGRAM) nix-profile.sh $(DESTDIR)$(sysconfdir)/profile.d/nix.sh $(INSTALL) -d $(DESTDIR)$(libexecdir)/nix $(INSTALL_DATA) readmanifest.pm $(DESTDIR)$(libexecdir)/nix $(INSTALL_DATA) readconfig.pm $(DESTDIR)$(libexecdir)/nix $(INSTALL_PROGRAM) download-using-manifests.pl $(DESTDIR)$(libexecdir)/nix + $(INSTALL_PROGRAM) find-runtime-roots.pl $(DESTDIR)$(libexecdir)/nix $(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix include ../substitute.mk @@ -27,4 +28,5 @@ EXTRA_DIST = nix-collect-garbage.in \ nix-build.in \ download-using-manifests.pl.in \ generate-patches.pl.in \ - nix-pack-closure.in nix-unpack-closure.in + nix-pack-closure.in nix-unpack-closure.in \ + find-runtime-roots.pl.in diff --git a/scripts/find-runtime-roots.pl.in b/scripts/find-runtime-roots.pl.in new file mode 100644 index 000000000..3e55ee445 --- /dev/null +++ b/scripts/find-runtime-roots.pl.in @@ -0,0 +1,58 @@ +#! @perl@ -w + +use strict; + +my $procDir = "/proc"; + + +sub readProc { + return unless -d $procDir; + + opendir DIR, $procDir or return; + + foreach my $name (readdir DIR) { + next unless $name =~ /^\d+$/; + + my $process = "$procDir/$name"; + + #print STDERR "=== $process\n"; + + my $target; + print "$target\n" if $target = readlink "$process/exe"; + print "$target\n" if $target = readlink "$process/cwd"; + + if (opendir FDS, "$process/fd") { + foreach my $name (readdir FDS) { + $target = readlink "$process/fd/$name"; + print "$target\n" if $target && substr($target, 0, 1) eq "/"; + } + closedir FDS; + } + + if (open MAP, "<$process/maps") { + while () { + next unless /^ \s* \S+ \s+ \S+ \s+ \S+ \s+ \S+ \s+ \S+ \s+ (\/\S+) \s* $/x; + print "$1\n"; + } + close MAP; + } + } + + closedir DIR; +} + + +sub lsof { + return unless open LSOF, "lsof -b -w -F n |"; + + while () { + next unless /^n (\/ .*)$/x; + print $1, "\n"; + } + + close LSOF; +} + + +readProc; +lsof;