Skip to content

Commit

Permalink
Merge branch 'cvmfs-2.4' into devel
Browse files Browse the repository at this point in the history
  • Loading branch information
jblomer committed Nov 15, 2017
2 parents 0f0c867 + f91a87b commit 8ea5eb4
Show file tree
Hide file tree
Showing 17 changed files with 169 additions and 60 deletions.
4 changes: 3 additions & 1 deletion ChangeLog
Expand Up @@ -9,7 +9,9 @@
* Make `true` to be a valid boolean option

2.4.3:
* Work around for alien cache on BeeGFS (CVM-1403)
* Turn cvmfs-config into Debian virtual package (CVM-1420)
* Invalidate inodes instead of dentries on reload/remount (CVM-1423)
* Workaround for alien cache on BeeGFS (CVM-1403)

2.4.2:
* Skip external files during garbage collection (CVM-1396)
Expand Down
2 changes: 1 addition & 1 deletion ci/cvmfs/deb.sh
Expand Up @@ -19,7 +19,7 @@ CVMFS_SOURCE_LOCATION="$1"
CVMFS_RESULT_LOCATION="$2"
CVMFS_NIGHTLY_BUILD_NUMBER="${3-0}"

CVMFS_CONFIG_PACKAGE="cvmfs-config-default_1.1-1_all.deb"
CVMFS_CONFIG_PACKAGE="cvmfs-config-default_1.6-1_all.deb"

# retrieve the upstream version string from CVMFS
cvmfs_version="$(get_cvmfs_version_from_cmake $CVMFS_SOURCE_LOCATION)"
Expand Down
2 changes: 1 addition & 1 deletion ci/cvmfs/rpm.sh
Expand Up @@ -19,7 +19,7 @@ CVMFS_SOURCE_LOCATION="$1"
CVMFS_RESULT_LOCATION="$2"
CVMFS_NIGHTLY_BUILD_NUMBER="${3-0}"

CVMFS_CONFIG_PACKAGE="cvmfs-config-default-1.2-1.noarch.rpm"
CVMFS_CONFIG_PACKAGE="cvmfs-config-default-1.4-1.noarch.rpm"

rpm_infra_dirs="BUILD RPMS SOURCES SRPMS TMP"
rpm_src_dir="${CVMFS_SOURCE_LOCATION}/packaging/rpm"
Expand Down
13 changes: 9 additions & 4 deletions cvmfs/duplex_fuse.h
Expand Up @@ -13,11 +13,11 @@ extern "C" {
// Empty structs have different sizes in C and C++, hence the dummy int
struct fuse_chan { int dummy; };
// Defined in t_fuse_evict.cc
extern unsigned fuse_lowlevel_notify_inval_entry_cnt;
static int __attribute__((used)) fuse_lowlevel_notify_inval_entry(
void *, unsigned long, const char *, size_t) // NOLINT (ulong from fuse)
extern unsigned fuse_lowlevel_notify_inval_inode_cnt;
static int __attribute__((used)) fuse_lowlevel_notify_inval_inode(
void *, unsigned /*fuse_ino_t*/, off_t, off_t) // NOLINT (ulong from fuse)
{
fuse_lowlevel_notify_inval_entry_cnt++;
fuse_lowlevel_notify_inval_inode_cnt++;
return -1;
}
}
Expand All @@ -32,6 +32,11 @@ static int __attribute__((used)) fuse_lowlevel_notify_inval_entry(
{
abort();
}
static int __attribute__((used)) fuse_lowlevel_notify_inval_inode(
void *, fuse_ino_t, off_t, off_t) // NOLINT
{
abort();
}
}
#endif
#endif
Expand Down
27 changes: 11 additions & 16 deletions cvmfs/fuse_evict.cc
Expand Up @@ -88,7 +88,7 @@ FuseInvalidator::~FuseInvalidator() {
}


void FuseInvalidator::InvalidateDentries(Handle *handle) {
void FuseInvalidator::InvalidateInodes(Handle *handle) {
assert(handle != NULL);
char c = 'I';
WritePipe(pipe_ctrl_[1], &c, 1);
Expand Down Expand Up @@ -130,30 +130,25 @@ void *FuseInvalidator::MainInvalidator(void *data) {

// We must not hold a lock when calling fuse_lowlevel_notify_inval_entry.
// Therefore, we first copy all the inodes into a temporary data structure.
EvictableObject evictable_object;
glue::InodeTracker::Cursor cursor(
invalidator->inode_tracker_->BeginEnumerate());
while (invalidator->inode_tracker_->Next(
&cursor, &evictable_object.inode, &evictable_object.name))
uint64_t inode;
while (invalidator->inode_tracker_->NextInode(&cursor, &inode))
{
invalidator->evict_list_.PushBack(evictable_object);
invalidator->evict_list_.PushBack(inode);
}
invalidator->inode_tracker_->EndEnumerate(&cursor);

unsigned i = 0;
unsigned N = invalidator->evict_list_.size();
while (i < N) {
evictable_object = invalidator->evict_list_.At(i);
if (evictable_object.inode == 0)
evictable_object.inode = FUSE_ROOT_ID;
// Can return non-zero value if parent entry was already evicted
fuse_lowlevel_notify_inval_entry(
*invalidator->fuse_channel_,
evictable_object.inode,
evictable_object.name.GetChars(),
evictable_object.name.GetLength());
LogCvmfs(kLogCvmfs, kLogDebug, "evicting <%" PRIu64 ">/%s",
evictable_object.inode, evictable_object.name.c_str());
uint64_t inode = invalidator->evict_list_.At(i);
if (inode == 0)
inode = FUSE_ROOT_ID;
// Can fail, e.g. the inode might be already evicted
fuse_lowlevel_notify_inval_inode(
*invalidator->fuse_channel_, inode, 0, 0);
LogCvmfs(kLogCvmfs, kLogDebug, "evicting inode %" PRIu64, inode);

if ((++i % kCheckTimeoutFreqOps) == 0) {
if (platform_monotonic_time() >= deadline) {
Expand Down
12 changes: 2 additions & 10 deletions cvmfs/fuse_evict.h
Expand Up @@ -64,7 +64,7 @@ class FuseInvalidator : SingleCopy {
struct fuse_chan **fuse_channel);
~FuseInvalidator();
void Spawn();
void InvalidateDentries(Handle *handle);
void InvalidateInodes(Handle *handle);

private:
/**
Expand All @@ -81,14 +81,6 @@ class FuseInvalidator : SingleCopy {
*/
static const unsigned kCheckTimeoutFreqOps; // = 256

/**
* The information given to fuse_lowlevel_notify_inval_entry
*/
struct EvictableObject {
uint64_t inode;
NameString name;
};

static void *MainInvalidator(void *data);

glue::InodeTracker *inode_tracker_;
Expand All @@ -101,7 +93,7 @@ class FuseInvalidator : SingleCopy {
* thread should be shut down.
*/
atomic_int32 terminated_;
BigVector<EvictableObject> evict_list_;
BigVector<uint64_t> evict_list_;
}; // class FuseInvalidator

#endif // CVMFS_FUSE_EVICT_H_
4 changes: 2 additions & 2 deletions cvmfs/fuse_remount.cc
Expand Up @@ -54,7 +54,7 @@ FuseRemounter::Status FuseRemounter::Check() {
"new catalog revision available, "
"draining out meta-data caches");
invalidator_handle_.Reset();
invalidator_->InvalidateDentries(&invalidator_handle_);
invalidator_->InvalidateInodes(&invalidator_handle_);
atomic_inc32(&drainout_mode_);
// drainout_mode_ == 2, IsInDrainoutMode is now 'true'
} else {
Expand Down Expand Up @@ -112,7 +112,7 @@ void FuseRemounter::EnterMaintenanceMode() {

// Flush caches before reload of fuse module
invalidator_handle_.Reset();
invalidator_->InvalidateDentries(&invalidator_handle_);
invalidator_->InvalidateInodes(&invalidator_handle_);
invalidator_handle_.WaitFor();
}

Expand Down
43 changes: 40 additions & 3 deletions cvmfs/glue_buffer.h
Expand Up @@ -394,6 +394,14 @@ class InodeMap {

class InodeReferences {
public:
/**
* Used to enumerate all inodes
*/
struct Cursor {
Cursor() : idx(0) { }
uint32_t idx;
};

InodeReferences() {
map_.Init(16, 0, hasher_inode);
}
Expand Down Expand Up @@ -425,6 +433,24 @@ class InodeReferences {
map_.Clear();
}

Cursor BeginEnumerate() {
return Cursor();
}

bool Next(Cursor *cursor, uint64_t *inode) {
uint64_t empty_key = map_.empty_key();
while (cursor->idx < map_.capacity()) {
if (map_.keys()[cursor->idx] == empty_key) {
cursor->idx++;
continue;
}
*inode = map_.keys()[cursor->idx];
cursor->idx++;
return true;
}
return false;
}

private:
SmallHashDynamic<uint64_t, uint32_t> map_;
};
Expand All @@ -442,8 +468,14 @@ class InodeTracker {
* Used to actively evict all known paths from kernel caches
*/
struct Cursor {
explicit Cursor(const PathStore::Cursor &c) : csr_paths(c) { }
explicit Cursor(
const PathStore::Cursor &p,
const InodeReferences::Cursor &i)
: csr_paths(p)
, csr_inos(i)
{ }
PathStore::Cursor csr_paths;
InodeReferences::Cursor csr_inos;
};

// Cannot be moved to the statistics manager because it has to survive
Expand Down Expand Up @@ -540,10 +572,11 @@ class InodeTracker {

Cursor BeginEnumerate() {
Lock();
return Cursor(path_map_.path_store()->BeginEnumerate());
return Cursor(path_map_.path_store()->BeginEnumerate(),
inode_references_.BeginEnumerate());
}

bool Next(Cursor *cursor, uint64_t *inode_parent, NameString *name) {
bool NextEntry(Cursor *cursor, uint64_t *inode_parent, NameString *name) {
shash::Md5 parent_md5;
StringRef name_ref;
bool result = path_map_.path_store()->Next(
Expand All @@ -558,6 +591,10 @@ class InodeTracker {
return true;
}

bool NextInode(Cursor *cursor, uint64_t *inode) {
return inode_references_.Next(&(cursor->csr_inos), inode);
}

void EndEnumerate(Cursor *cursor) {
Unlock();
}
Expand Down
24 changes: 24 additions & 0 deletions cvmfs/talk.cc
Expand Up @@ -587,6 +587,30 @@ void *TalkManager::MainResponder(void *data) {
(*i)->so_version + ")\n";
}
talk_mgr->Answer(con_fd, history_str);
} else if (line == "vfs inodes") {
string result;
glue::InodeTracker::Cursor cursor(
mount_point->inode_tracker()->BeginEnumerate());
uint64_t inode;
while (mount_point->inode_tracker()->NextInode(&cursor, &inode)) {
result += StringifyInt(inode) + "\n";
}
mount_point->inode_tracker()->EndEnumerate(&cursor);
talk_mgr->Answer(con_fd, result);
} else if (line == "vfs entries") {
string result;
glue::InodeTracker::Cursor cursor(
mount_point->inode_tracker()->BeginEnumerate());
uint64_t inode_parent;
NameString name;
while (mount_point->inode_tracker()->NextEntry(
&cursor, &inode_parent, &name))
{
result += "<" + StringifyInt(inode_parent) + ">/" + name.ToString() +
"\n";
}
mount_point->inode_tracker()->EndEnumerate(&cursor);
talk_mgr->Answer(con_fd, result);
} else if (line == "version") {
string version_str = string(VERSION) + " (CernVM-FS Fuse Module)\n" +
cvmfs::loader_exports_->loader_version + " (Loader)\n";
Expand Down
6 changes: 6 additions & 0 deletions packaging/debian/config-default/changelog
@@ -1,3 +1,9 @@
cvmfs-config-default (1.6-1) lucid; urgency=low

* Turn into virtual package

-- Dave Dykstra <dwd@fnal.gov> Tue, 14 Nov 2017 16:00:00 +0000

cvmfs-config-default (1.5-1) lucid; urgency=low

* Update comment on config repository
Expand Down
2 changes: 1 addition & 1 deletion packaging/debian/config-default/control
Expand Up @@ -9,7 +9,7 @@ Homepage: http://cernvm.cern.ch/portal/filesystem
Package: cvmfs-config-default
Architecture: all
Replaces: cvmfs-keys
Conflicts: cvmfs-keys
Conflicts: cvmfs-keys, cvmfs-config
Breaks: cvmfs-keys, cvmfs (<< 2.1.20), cvmfs-server (<< 2.1.20)
Provides: cvmfs-config
Description: CernVM File System Default Configuration
Expand Down
6 changes: 6 additions & 0 deletions packaging/debian/config-none/changelog
@@ -1,3 +1,9 @@
cvmfs-config-none (1.1-0) lucid; urgency=low

* Turn into virtual package

-- Dave Dykstra <dwd@fnal.gov> Tue, 14 Nov 2017 16:00:00 +0000

cvmfs-config-none (1.0-2) lucid; urgency=low

* Fix packaging errors
Expand Down
1 change: 1 addition & 0 deletions packaging/debian/config-none/control
Expand Up @@ -10,6 +10,7 @@ Package: cvmfs-config-none
Architecture: all
Breaks: cvmfs (<< 2.1.20), cvmfs-server (<< 2.1.20)
Provides: cvmfs-config
Conflicts: cvmfs-config
Description: CernVM File System Empty Configuration
Empty package to fulfill the "cvmfs-config" dependency of cvmfs. Can be used
to provide custom configuration to CernVM-FS.
2 changes: 1 addition & 1 deletion packaging/debian/cvmfs/control
Expand Up @@ -9,7 +9,7 @@ Homepage: http://cernvm.cern.ch/portal/filesystem
Package: cvmfs
Architecture: i386 amd64 armhf arm64
#Pre-Depends: ${misc:Pre-Depends} (preparation for multiarch support)
Depends: cvmfs-config, bash, coreutils, grep, gawk, sed, perl, psmisc, autofs, fuse, curl, attr, libfuse2, debianutils, libc-bin, sysvinit-utils, zlib1g, gdb, uuid-dev, uuid
Depends: cvmfs-config-default | cvmfs-config, bash, coreutils, grep, gawk, sed, perl, psmisc, autofs, fuse, curl, attr, libfuse2, debianutils, libc-bin, sysvinit-utils, zlib1g, gdb, uuid-dev, uuid
Recommends: autofs (>= 5.1.2)
#Multi-Arch: same (preparation for multiarch support)
Homepage: http://cernvm.cern.ch
Expand Down
22 changes: 22 additions & 0 deletions test/src/076-mountover/main
@@ -0,0 +1,22 @@

cvmfs_test_name="Mount over a directory in cvmfs and reload"

cleanup() {
sudo umount /cvmfs/cvmfs-config.cern.ch/etc/cvmfs
}

cvmfs_run_test() {
logfile=$1

cvmfs_mount cvmfs-config.cern.ch || return 1
sudo mount -t proc none /cvmfs/cvmfs-config.cern.ch/etc/cvmfs || return 2
trap cleanup EXIT HUP INT TERM

ls /cvmfs/cvmfs-config.cern.ch/etc/cvmfs/self || return 10
sudo cvmfs_config reload cvmfs-config.cern.ch || return 11

ls /cvmfs/cvmfs-config.cern.ch/etc/cvmfs/self || return 20

return 0
}

18 changes: 9 additions & 9 deletions test/unittests/t_fuse_evict.cc
Expand Up @@ -9,7 +9,7 @@
#include "util/string.h"

extern "C" {
unsigned fuse_lowlevel_notify_inval_entry_cnt = 0;
unsigned fuse_lowlevel_notify_inval_inode_cnt = 0;
}

class T_FuseInvalidator : public ::testing::Test {
Expand Down Expand Up @@ -48,14 +48,14 @@ TEST_F(T_FuseInvalidator, StartStop) {
TEST_F(T_FuseInvalidator, InvalidateTimeout) {
FuseInvalidator::Handle handle(0);
EXPECT_FALSE(handle.IsDone());
invalidator_->InvalidateDentries(&handle);
invalidator_->InvalidateInodes(&handle);
handle.WaitFor();
EXPECT_TRUE(handle.IsDone());

invalidator_->terminated_ = 1;
FuseInvalidator::Handle handle2(1000000);
EXPECT_FALSE(handle2.IsDone());
invalidator_->InvalidateDentries(&handle2);
invalidator_->InvalidateInodes(&handle2);
handle2.WaitFor();
EXPECT_TRUE(handle2.IsDone());
}
Expand All @@ -70,26 +70,26 @@ TEST_F(T_FuseInvalidator, InvalidateOps) {

FuseInvalidator::Handle handle(0);
EXPECT_FALSE(handle.IsDone());
invalidator_->InvalidateDentries(&handle);
invalidator_->InvalidateInodes(&handle);
handle.WaitFor();
EXPECT_TRUE(handle.IsDone());
EXPECT_EQ(FuseInvalidator::kCheckTimeoutFreqOps,
fuse_lowlevel_notify_inval_entry_cnt);
fuse_lowlevel_notify_inval_inode_cnt);

FuseInvalidator::Handle handle2(1000000);
EXPECT_FALSE(handle2.IsDone());
invalidator_->InvalidateDentries(&handle2);
invalidator_->InvalidateInodes(&handle2);
handle2.WaitFor();
EXPECT_TRUE(handle2.IsDone());
EXPECT_EQ(FuseInvalidator::kCheckTimeoutFreqOps + 1024,
fuse_lowlevel_notify_inval_entry_cnt);
fuse_lowlevel_notify_inval_inode_cnt);

invalidator_->terminated_ = 1;
handle2.Reset();
EXPECT_FALSE(handle2.IsDone());
invalidator_->InvalidateDentries(&handle2);
invalidator_->InvalidateInodes(&handle2);
handle2.WaitFor();
EXPECT_TRUE(handle2.IsDone());
EXPECT_EQ((2 * FuseInvalidator::kCheckTimeoutFreqOps) + 1024,
fuse_lowlevel_notify_inval_entry_cnt);
fuse_lowlevel_notify_inval_inode_cnt);
}

0 comments on commit 8ea5eb4

Please sign in to comment.