Browse Source

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.
nix
Eelco Dolstra 10 years ago
parent
commit
def5160b61
  1. 13
      doc/manual/release-notes.xml
  2. 9
      src/libstore/build.cc
  3. 2
      src/libstore/gc.cc
  4. 61
      src/libstore/local-store.cc
  5. 5
      src/libstore/local-store.hh
  6. 9
      src/libstore/optimise-store.cc
  7. 4
      src/libutil/Makefile.am
  8. 49
      src/libutil/immutable.cc
  9. 10
      src/libutil/immutable.hh
  10. 3
      src/libutil/util.cc

13
doc/manual/release-notes.xml

@ -8,10 +8,17 @@
<!--==================================================================-->
<section xml:id="ssec-relnotes-1.3"><title>Release 1.3 (January 2, 2013)</title>
<section xml:id="ssec-relnotes-1.3"><title>Release 1.3 (January 3, 2013)</title>
<para>This is primarily a bug fix release. It has contributions from
Eelco Dolstra and Stuart Pernsteiner.</para>
<para>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.)</para>
<para>This release has contributions from Eelco Dolstra and Stuart
Pernsteiner.</para>
</section>

9
src/libstore/build.cc

@ -7,7 +7,6 @@
#include "local-store.hh"
#include "util.hh"
#include "archive.hh"
#include "immutable.hh"
#include <map>
#include <sstream>
@ -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

2
src/libstore/gc.cc

@ -1,7 +1,6 @@
#include "globals.hh"
#include "misc.hh"
#include "local-store.hh"
#include "immutable.hh"
#include <boost/shared_ptr.hpp>
@ -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);

61
src/libstore/local-store.cc

@ -5,7 +5,6 @@
#include "pathlocks.hh"
#include "worker-protocol.hh"
#include "derivations.hh"
#include "immutable.hh"
#include <iostream>
#include <algorithm>
@ -25,6 +24,12 @@
#include <sys/mount.h>
#endif
#if HAVE_LINUX_FS_H
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <errno.h>
#endif
#include <sqlite3.h>
@ -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)

5
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);

9
src/libstore/optimise-store.cc

@ -2,7 +2,6 @@
#include "util.hh"
#include "local-store.hh"
#include "immutable.hh"
#include "globals.hh"
#include <sys/types.h>
@ -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();

4
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 += \

49
src/libutil/immutable.cc

@ -1,49 +0,0 @@
#include "config.h"
#include "immutable.hh"
#include "util.hh"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#if HAVE_LINUX_FS_H
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <errno.h>
#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
}
}

10
src/libutil/immutable.hh

@ -1,10 +0,0 @@
#pragma once
#include <types.hh>
namespace nix {
/* Make the given path mutable. */
void makeMutable(const Path & path);
}

3
src/libutil/util.cc

@ -13,7 +13,6 @@
#include <limits.h>
#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;

Loading…
Cancel
Save