From def5160b614a59a0aa96fe2252e3daa00146e061 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 3 Jan 2013 12:59:23 +0100 Subject: [PATCH] Clear any immutable bits in the Nix store Doing this once makes subsequent operations like garbage collecting more efficient since we don't have to call makeMutable() first. --- doc/manual/release-notes.xml | 13 ++++++-- src/libstore/build.cc | 9 +---- src/libstore/gc.cc | 2 -- src/libstore/local-store.cc | 61 +++++++++++++++++++++++++++++++++- src/libstore/local-store.hh | 5 +-- src/libstore/optimise-store.cc | 9 ----- src/libutil/Makefile.am | 4 +-- src/libutil/immutable.cc | 49 --------------------------- src/libutil/immutable.hh | 10 ------ src/libutil/util.cc | 3 -- 10 files changed, 76 insertions(+), 89 deletions(-) delete mode 100644 src/libutil/immutable.cc delete mode 100644 src/libutil/immutable.hh diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml index 9560c055b..60c119cb7 100644 --- a/doc/manual/release-notes.xml +++ b/doc/manual/release-notes.xml @@ -8,10 +8,17 @@ -
Release 1.3 (January 2, 2013) +
Release 1.3 (January 3, 2013) -This is primarily a bug fix release. It has contributions from -Eelco Dolstra and Stuart Pernsteiner. +This is primarily a bug fix release. When this version is first +run on Linux, it removes any immutable bits from the Nix store and +increases the schema version of the Nix store. (The previous release +removed support for setting the immutable bit; this release clears any +remaining immutable bits to make certain operations more +efficient.) + +This release has contributions from Eelco Dolstra and Stuart +Pernsteiner.
diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 6ff38b0c0..75802c324 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -7,7 +7,6 @@ #include "local-store.hh" #include "util.hh" #include "archive.hh" -#include "immutable.hh" #include #include @@ -1383,10 +1382,8 @@ void replaceValidPath(const Path & storePath, const Path tmpPath) way first. We'd better not be interrupted here, because if we're repairing (say) Glibc, we end up with a broken system. */ Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % rand()).str(); - if (pathExists(storePath)) { - makeMutable(storePath); + if (pathExists(storePath)) rename(storePath.c_str(), oldPath.c_str()); - } if (rename(tmpPath.c_str(), storePath.c_str()) == -1) throw SysError(format("moving `%1%' to `%2%'") % tmpPath % storePath); if (pathExists(oldPath)) @@ -1911,10 +1908,6 @@ void DerivationGoal::startBuilder() if (S_ISDIR(st.st_mode)) dirsInChroot[*i] = *i; else { - /* Creating a hard link to *i is impossible if its - immutable bit is set. So clear it first. */ - makeMutable(*i); - Path p = chrootRootDir + *i; if (link(i->c_str(), p.c_str()) == -1) { /* Hard-linking fails if we exceed the maximum diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 4385e4456..a8fa1108b 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -1,7 +1,6 @@ #include "globals.hh" #include "misc.hh" #include "local-store.hh" -#include "immutable.hh" #include @@ -456,7 +455,6 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path) // if the path was not valid, need to determine the actual // size. state.bytesInvalidated += size; - makeMutable(path.c_str()); // Mac OS X cannot rename directories if they are read-only. if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1) throw SysError(format("making `%1%' writable") % path); diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 26b4cfd8c..87d6e6a94 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -5,7 +5,6 @@ #include "pathlocks.hh" #include "worker-protocol.hh" #include "derivations.hh" -#include "immutable.hh" #include #include @@ -25,6 +24,12 @@ #include #endif +#if HAVE_LINUX_FS_H +#include +#include +#include +#endif + #include @@ -292,6 +297,7 @@ LocalStore::LocalStore(bool reserveSpace) curSchema = getSchema(); if (curSchema < 6) upgradeStore6(); + else if (curSchema < 7) upgradeStore7(); writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str()); @@ -1787,6 +1793,59 @@ void LocalStore::upgradeStore6() } +#if defined(FS_IOC_SETFLAGS) && defined(FS_IOC_GETFLAGS) && defined(FS_IMMUTABLE_FL) + +static void makeMutable(const Path & path) +{ + checkInterrupt(); + + struct stat st = lstat(path); + + if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) return; + + if (S_ISDIR(st.st_mode)) { + Strings names = readDirectory(path); + foreach (Strings::iterator, i, names) + makeMutable(path + "/" + *i); + } + + /* The O_NOFOLLOW is important to prevent us from changing the + mutable bit on the target of a symlink (which would be a + security hole). */ + AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW); + if (fd == -1) { + if (errno == ELOOP) return; // it's a symlink + throw SysError(format("opening file `%1%'") % path); + } + + unsigned int flags = 0, old; + + /* Silently ignore errors getting/setting the immutable flag so + that we work correctly on filesystems that don't support it. */ + if (ioctl(fd, FS_IOC_GETFLAGS, &flags)) return; + old = flags; + flags &= ~FS_IMMUTABLE_FL; + if (old == flags) return; + if (ioctl(fd, FS_IOC_SETFLAGS, &flags)) return; +} + +/* Upgrade from schema 6 (Nix 0.15) to schema 7 (Nix >= 1.3). */ +void LocalStore::upgradeStore7() +{ + if (getuid() != 0) return; + printMsg(lvlError, "removing immutable bits from the Nix store (this may take a while)..."); + makeMutable(settings.nixStore); +} + +#else + +void LocalStore::upgradeStore7() +{ +} + +#endif + + void LocalStore::vacuumDB() { if (sqlite3_exec(db, "vacuum;", 0, 0, 0) != SQLITE_OK) diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 82ca791a3..2b0d71380 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -17,8 +17,8 @@ namespace nix { /* Nix store and database schema version. Version 1 (or 0) was Nix <= 0.7. Version 2 was Nix 0.8 and 0.9. Version 3 is Nix 0.10. Version 4 is Nix 0.11. Version 5 is Nix 0.12-0.16. Version 6 is - Nix 1.0. */ -const int nixSchemaVersion = 6; + Nix 1.0. Version 7 is Nix 1.3. */ +const int nixSchemaVersion = 7; extern string drvsLogDir; @@ -265,6 +265,7 @@ private: void updatePathInfo(const ValidPathInfo & info); void upgradeStore6(); + void upgradeStore7(); PathSet queryValidPathsOld(); ValidPathInfo queryPathInfoOld(const Path & path); diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 43b3c9b4f..e91c2b1ce 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -2,7 +2,6 @@ #include "util.hh" #include "local-store.hh" -#include "immutable.hh" #include "globals.hh" #include @@ -20,7 +19,6 @@ static void makeWritable(const Path & path) struct stat st; if (lstat(path.c_str(), &st)) throw SysError(format("getting attributes of path `%1%'") % path); - if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode)) makeMutable(path); if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1) throw SysError(format("changing writability of `%1%'") % path); } @@ -91,7 +89,6 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) if (!pathExists(linkPath)) { /* Nope, create a hard link in the links directory. */ - makeMutable(path); if (link(path.c_str(), linkPath.c_str()) == 0) return; if (errno != EEXIST) throw SysError(format("cannot link `%1%' to `%2%'") % linkPath % path); @@ -123,12 +120,6 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) its timestamp back to 0. */ MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : ""); - /* If ‘linkPath’ is immutable, we can't create hard links to it, - so make it mutable first. We also have to make ‘path’ mutable, - otherwise rename() will fail to delete it. */ - makeMutable(path); - makeMutable(linkPath); - Path tempLink = (format("%1%/.tmp-link-%2%-%3%") % settings.nixStore % getpid() % rand()).str(); diff --git a/src/libutil/Makefile.am b/src/libutil/Makefile.am index 4a3523f3b..fe896eec5 100644 --- a/src/libutil/Makefile.am +++ b/src/libutil/Makefile.am @@ -1,12 +1,12 @@ pkglib_LTLIBRARIES = libutil.la libutil_la_SOURCES = util.cc hash.cc serialise.cc \ - archive.cc xml-writer.cc immutable.cc + archive.cc xml-writer.cc libutil_la_LIBADD = ../boost/format/libformat.la pkginclude_HEADERS = util.hh hash.hh serialise.hh \ - archive.hh xml-writer.hh types.hh immutable.hh + archive.hh xml-writer.hh types.hh if !HAVE_OPENSSL libutil_la_SOURCES += \ diff --git a/src/libutil/immutable.cc b/src/libutil/immutable.cc deleted file mode 100644 index 766af4939..000000000 --- a/src/libutil/immutable.cc +++ /dev/null @@ -1,49 +0,0 @@ -#include "config.h" - -#include "immutable.hh" -#include "util.hh" - -#include -#include -#include - -#if HAVE_LINUX_FS_H -#include -#include -#include -#endif - -namespace nix { - - -void makeMutable(const Path & path) -{ -#if defined(FS_IOC_SETFLAGS) && defined(FS_IOC_GETFLAGS) && defined(FS_IMMUTABLE_FL) - - /* Don't even try if we're not root. One day we should support - the CAP_LINUX_IMMUTABLE capability. */ - if (getuid() != 0) return; - - /* The O_NOFOLLOW is important to prevent us from changing the - mutable bit on the target of a symlink (which would be a - security hole). */ - AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW); - if (fd == -1) { - if (errno == ELOOP) return; // it's a symlink - throw SysError(format("opening file `%1%'") % path); - } - - unsigned int flags = 0, old; - - /* Silently ignore errors getting/setting the immutable flag so - that we work correctly on filesystems that don't support it. */ - if (ioctl(fd, FS_IOC_GETFLAGS, &flags)) return; - old = flags; - flags &= ~FS_IMMUTABLE_FL; - if (old == flags) return; - if (ioctl(fd, FS_IOC_SETFLAGS, &flags)) return; -#endif -} - - -} diff --git a/src/libutil/immutable.hh b/src/libutil/immutable.hh deleted file mode 100644 index 8e98b76a4..000000000 --- a/src/libutil/immutable.hh +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -namespace nix { - -/* Make the given path mutable. */ -void makeMutable(const Path & path); - -} diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 1308eac31..7874329c7 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -13,7 +13,6 @@ #include #include "util.hh" -#include "immutable.hh" extern char * * environ; @@ -305,8 +304,6 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed) struct stat st = lstat(path); - if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode)) makeMutable(path); - if (!S_ISDIR(st.st_mode) && st.st_nlink == 1) bytesFreed += st.st_blocks * 512;