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.
This commit is contained in:
parent
0a4e90395c
commit
def5160b61
10 changed files with 76 additions and 89 deletions
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 += \
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <types.hh>
|
||||
|
||||
namespace nix {
|
||||
|
||||
/* Make the given path mutable. */
|
||||
void makeMutable(const Path & path);
|
||||
|
||||
}
|
|
@ -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…
Reference in a new issue