Protect from race conditions happening when the same FsBlob is open multiple times

This commit is contained in:
Sebastian Messmer 2015-09-30 14:05:05 +02:00
parent e3d2fdb2fd
commit 752be4415c
10 changed files with 58 additions and 26 deletions

View File

@ -28,8 +28,8 @@ namespace fsblobstore {
//TODO Factor out a DirEntryList class //TODO Factor out a DirEntryList class
DirBlob::DirBlob(unique_ref<Blob> blob, FsBlobStore *fsBlobStore) : DirBlob::DirBlob(unique_ref<Blob> blob, FsBlobStore *fsBlobStore, std::function<void()> onDestruct) :
FsBlob(std::move(blob)), _fsBlobStore(fsBlobStore), _entries(), _changed(false) { FsBlob(std::move(blob), onDestruct), _fsBlobStore(fsBlobStore), _entries(), _changed(false) {
ASSERT(magicNumber() == MagicNumbers::DIR, "Loaded blob is not a directory"); ASSERT(magicNumber() == MagicNumbers::DIR, "Loaded blob is not a directory");
_readEntriesFromBlob(); _readEntriesFromBlob();
} }
@ -43,9 +43,9 @@ void DirBlob::flush() {
baseBlob().flush(); baseBlob().flush();
} }
unique_ref<DirBlob> DirBlob::InitializeEmptyDir(unique_ref<Blob> blob, FsBlobStore *fsBlobStore) { unique_ref<DirBlob> DirBlob::InitializeEmptyDir(unique_ref<Blob> blob, FsBlobStore *fsBlobStore, std::function<void()> onDestruct) {
InitializeBlobWithMagicNumber(blob.get(), MagicNumbers::DIR); InitializeBlobWithMagicNumber(blob.get(), MagicNumbers::DIR);
return make_unique_ref<DirBlob>(std::move(blob), fsBlobStore); return make_unique_ref<DirBlob>(std::move(blob), fsBlobStore, onDestruct);
} }
void DirBlob::_writeEntriesToBlob() { void DirBlob::_writeEntriesToBlob() {

View File

@ -43,9 +43,10 @@ namespace cryfs {
}; };
static cpputils::unique_ref<DirBlob> InitializeEmptyDir(cpputils::unique_ref<blobstore::Blob> blob, static cpputils::unique_ref<DirBlob> InitializeEmptyDir(cpputils::unique_ref<blobstore::Blob> blob,
FsBlobStore *fsBlobStore); FsBlobStore *fsBlobStore,
std::function<void()> onDestruct);
DirBlob(cpputils::unique_ref<blobstore::Blob> blob, FsBlobStore *fsBlobStore); DirBlob(cpputils::unique_ref<blobstore::Blob> blob, FsBlobStore *fsBlobStore, std::function<void()> onDestruct);
virtual ~DirBlob(); virtual ~DirBlob();

View File

@ -11,13 +11,13 @@ using cpputils::make_unique_ref;
namespace cryfs { namespace cryfs {
namespace fsblobstore { namespace fsblobstore {
FileBlob::FileBlob(unique_ref<Blob> blob) FileBlob::FileBlob(unique_ref<Blob> blob, std::function<void()> onDestruct)
: FsBlob(std::move(blob)) { : FsBlob(std::move(blob), onDestruct) {
} }
unique_ref<FileBlob> FileBlob::InitializeEmptyFile(unique_ref<Blob> blob) { unique_ref<FileBlob> FileBlob::InitializeEmptyFile(unique_ref<Blob> blob, std::function<void()> onDestruct) {
InitializeBlobWithMagicNumber(blob.get(), MagicNumbers::FILE); InitializeBlobWithMagicNumber(blob.get(), MagicNumbers::FILE);
return make_unique_ref<FileBlob>(std::move(blob)); return make_unique_ref<FileBlob>(std::move(blob), onDestruct);
} }
ssize_t FileBlob::read(void *target, uint64_t offset, uint64_t count) const { ssize_t FileBlob::read(void *target, uint64_t offset, uint64_t count) const {

View File

@ -9,9 +9,9 @@ namespace cryfs {
class FileBlob: public FsBlob { class FileBlob: public FsBlob {
public: public:
static cpputils::unique_ref<FileBlob> InitializeEmptyFile(cpputils::unique_ref<blobstore::Blob> blob); static cpputils::unique_ref<FileBlob> InitializeEmptyFile(cpputils::unique_ref<blobstore::Blob> blob, std::function<void()> onDestruct);
FileBlob(cpputils::unique_ref<blobstore::Blob> blob); FileBlob(cpputils::unique_ref<blobstore::Blob> blob, std::function<void()> onDestruct);
ssize_t read(void *target, uint64_t offset, uint64_t count) const; ssize_t read(void *target, uint64_t offset, uint64_t count) const;

View File

@ -3,6 +3,7 @@
#include <messmer/cpp-utils/pointer/unique_ref.h> #include <messmer/cpp-utils/pointer/unique_ref.h>
#include <messmer/blobstore/interface/Blob.h> #include <messmer/blobstore/interface/Blob.h>
#include <functional>
namespace cryfs { namespace cryfs {
namespace fsblobstore { namespace fsblobstore {
@ -14,7 +15,7 @@ namespace cryfs {
blockstore::Key key() const; blockstore::Key key() const;
protected: protected:
FsBlob(cpputils::unique_ref<blobstore::Blob> baseBlob); FsBlob(cpputils::unique_ref<blobstore::Blob> baseBlob, std::function<void()> onDestruct);
blobstore::Blob &baseBlob(); blobstore::Blob &baseBlob();
const blobstore::Blob &baseBlob() const; const blobstore::Blob &baseBlob() const;
@ -29,14 +30,17 @@ namespace cryfs {
cpputils::unique_ref<blobstore::Blob> releaseBaseBlob(); cpputils::unique_ref<blobstore::Blob> releaseBaseBlob();
cpputils::unique_ref<blobstore::Blob> _baseBlob; cpputils::unique_ref<blobstore::Blob> _baseBlob;
std::function<void()> _onDestruct;
DISALLOW_COPY_AND_ASSIGN(FsBlob); DISALLOW_COPY_AND_ASSIGN(FsBlob);
}; };
inline FsBlob::FsBlob(cpputils::unique_ref<blobstore::Blob> baseBlob): _baseBlob(std::move(baseBlob)) { inline FsBlob::FsBlob(cpputils::unique_ref<blobstore::Blob> baseBlob, std::function<void()> onDestruct)
: _baseBlob(std::move(baseBlob)), _onDestruct(onDestruct) {
} }
inline FsBlob::~FsBlob() { inline FsBlob::~FsBlob() {
_onDestruct();
} }
inline blockstore::Key FsBlob::key() const { inline blockstore::Key FsBlob::key() const {

View File

@ -9,6 +9,7 @@ using cpputils::unique_ref;
using cpputils::make_unique_ref; using cpputils::make_unique_ref;
using blobstore::BlobStore; using blobstore::BlobStore;
using boost::none; using boost::none;
using std::function;
namespace cryfs { namespace cryfs {
namespace fsblobstore { namespace fsblobstore {
@ -17,31 +18,42 @@ FsBlobStore::FsBlobStore(unique_ref<BlobStore> baseBlobStore): _baseBlobStore(st
} }
unique_ref<FileBlob> FsBlobStore::createFileBlob() { unique_ref<FileBlob> FsBlobStore::createFileBlob() {
return FileBlob::InitializeEmptyFile(_baseBlobStore->create()); auto blob = _baseBlobStore->create();
auto key = blob->key();
_openBlobs.lock(key);
return FileBlob::InitializeEmptyFile(std::move(blob), freeLockFunction(key));
} }
unique_ref<DirBlob> FsBlobStore::createDirBlob() { unique_ref<DirBlob> FsBlobStore::createDirBlob() {
auto blob = _baseBlobStore->create();
auto key = blob->key();
_openBlobs.lock(key);
//TODO Passed in fsBlobStore should be ParallelAccessFsBlobStore later //TODO Passed in fsBlobStore should be ParallelAccessFsBlobStore later
return DirBlob::InitializeEmptyDir(_baseBlobStore->create(), this); return DirBlob::InitializeEmptyDir(std::move(blob), this, freeLockFunction(key));
} }
unique_ref<SymlinkBlob> FsBlobStore::createSymlinkBlob(const bf::path &target) { unique_ref<SymlinkBlob> FsBlobStore::createSymlinkBlob(const bf::path &target) {
return SymlinkBlob::InitializeSymlink(_baseBlobStore->create(), target); auto blob = _baseBlobStore->create();
auto key = blob->key();
_openBlobs.lock(key);
return SymlinkBlob::InitializeSymlink(std::move(blob), target, freeLockFunction(key));
} }
boost::optional<unique_ref<FsBlob>> FsBlobStore::load(const blockstore::Key &key) { boost::optional<unique_ref<FsBlob>> FsBlobStore::load(const blockstore::Key &key) {
_openBlobs.lock(key);
auto blob = _baseBlobStore->load(key); auto blob = _baseBlobStore->load(key);
if (blob == none) { if (blob == none) {
return none; return none;
} }
unsigned char magicNumber = FsBlob::magicNumber(**blob); unsigned char magicNumber = FsBlob::magicNumber(**blob);
if (magicNumber == MagicNumbers::FILE) { if (magicNumber == MagicNumbers::FILE) {
return unique_ref<FsBlob>(make_unique_ref<FileBlob>(std::move(*blob))); return unique_ref<FsBlob>(make_unique_ref<FileBlob>(std::move(*blob), freeLockFunction(key)));
} else if (magicNumber == MagicNumbers::DIR) { } else if (magicNumber == MagicNumbers::DIR) {
//TODO Passed in fsBlobStore should be ParallelAccessFsBlobStore later //TODO Passed in fsBlobStore should be ParallelAccessFsBlobStore later
return unique_ref<FsBlob>(make_unique_ref<DirBlob>(std::move(*blob), this)); return unique_ref<FsBlob>(make_unique_ref<DirBlob>(std::move(*blob), this, freeLockFunction(key)));
} else if (magicNumber == MagicNumbers::SYMLINK) { } else if (magicNumber == MagicNumbers::SYMLINK) {
return unique_ref<FsBlob>(make_unique_ref<SymlinkBlob>(std::move(*blob))); return unique_ref<FsBlob>(make_unique_ref<SymlinkBlob>(std::move(*blob), freeLockFunction(key)));
} else { } else {
ASSERT(false, "Unknown magic number"); ASSERT(false, "Unknown magic number");
} }
@ -51,5 +63,11 @@ void FsBlobStore::remove(cpputils::unique_ref<FsBlob> blob) {
_baseBlobStore->remove(blob->releaseBaseBlob()); _baseBlobStore->remove(blob->releaseBaseBlob());
} }
function<void()> FsBlobStore::freeLockFunction(const blockstore::Key &key) {
return [this, key] {
_openBlobs.release(key);
};
}
} }
} }

View File

@ -1,6 +1,7 @@
#ifndef CRYFS_FSBLOBSTORE_FSBLOBSTORE_H #ifndef CRYFS_FSBLOBSTORE_FSBLOBSTORE_H
#define CRYFS_FSBLOBSTORE_FSBLOBSTORE_H #define CRYFS_FSBLOBSTORE_FSBLOBSTORE_H
#include <messmer/cpp-utils/lock/LockPool.h>
#include <messmer/cpp-utils/pointer/unique_ref.h> #include <messmer/cpp-utils/pointer/unique_ref.h>
#include <messmer/blobstore/interface/BlobStore.h> #include <messmer/blobstore/interface/BlobStore.h>
#include "FileBlob.h" #include "FileBlob.h"
@ -9,6 +10,8 @@
namespace cryfs { namespace cryfs {
namespace fsblobstore { namespace fsblobstore {
//TODO Test classes in fsblobstore
class FsBlobStore { class FsBlobStore {
public: public:
FsBlobStore(cpputils::unique_ref<blobstore::BlobStore> baseBlobStore); FsBlobStore(cpputils::unique_ref<blobstore::BlobStore> baseBlobStore);
@ -20,6 +23,10 @@ namespace cryfs {
void remove(cpputils::unique_ref<FsBlob> blob); void remove(cpputils::unique_ref<FsBlob> blob);
private: private:
std::function<void()> freeLockFunction(const blockstore::Key &key);
//Instead of locking open blobs, it would be faster to allow parallel access similar to parallelaccessstore.
cpputils::LockPool<blockstore::Key> _openBlobs;
cpputils::unique_ref<blobstore::BlobStore> _baseBlobStore; cpputils::unique_ref<blobstore::BlobStore> _baseBlobStore;
}; };
} }

View File

@ -14,17 +14,17 @@ namespace bf = boost::filesystem;
namespace cryfs { namespace cryfs {
namespace fsblobstore { namespace fsblobstore {
SymlinkBlob::SymlinkBlob(unique_ref<Blob> blob) SymlinkBlob::SymlinkBlob(unique_ref<Blob> blob, std::function<void()> onDestruct)
: FsBlob(std::move(blob)), _target(_readTargetFromBlob(baseBlob())) { : FsBlob(std::move(blob), onDestruct), _target(_readTargetFromBlob(baseBlob())) {
} }
unique_ref<SymlinkBlob> SymlinkBlob::InitializeSymlink(unique_ref<Blob> blob, const bf::path &target) { unique_ref<SymlinkBlob> SymlinkBlob::InitializeSymlink(unique_ref<Blob> blob, const bf::path &target, std::function<void()> onDestruct) {
string targetStr = target.native(); string targetStr = target.native();
blob->resize(1 + targetStr.size()); blob->resize(1 + targetStr.size());
unsigned char magicNumber = MagicNumbers::SYMLINK; unsigned char magicNumber = MagicNumbers::SYMLINK;
blob->write(&magicNumber, 0, 1); blob->write(&magicNumber, 0, 1);
blob->write(targetStr.c_str(), 1, targetStr.size()); blob->write(targetStr.c_str(), 1, targetStr.size());
return make_unique_ref<SymlinkBlob>(std::move(blob)); return make_unique_ref<SymlinkBlob>(std::move(blob), onDestruct);
} }
void SymlinkBlob::_checkMagicNumber(const Blob &blob) { void SymlinkBlob::_checkMagicNumber(const Blob &blob) {

View File

@ -11,9 +11,10 @@ namespace cryfs {
class SymlinkBlob: public FsBlob { class SymlinkBlob: public FsBlob {
public: public:
static cpputils::unique_ref<SymlinkBlob> InitializeSymlink(cpputils::unique_ref<blobstore::Blob> blob, static cpputils::unique_ref<SymlinkBlob> InitializeSymlink(cpputils::unique_ref<blobstore::Blob> blob,
const boost::filesystem::path &target); const boost::filesystem::path &target,
std::function<void()> onDestruct);
SymlinkBlob(cpputils::unique_ref<blobstore::Blob> blob); SymlinkBlob(cpputils::unique_ref<blobstore::Blob> blob, std::function<void()> onDestruct);
const boost::filesystem::path &target() const; const boost::filesystem::path &target() const;

View File

@ -27,6 +27,7 @@ using std::endl;
using std::vector; using std::vector;
//TODO Support files > 4GB //TODO Support files > 4GB
//TODO cryfs process doesn't seem to react to "kill". Needs "kill -9". Why? Furthermore, calling "fusermount -u" unmounts the fs, but the cryfs process keeps running. Why?
void showVersion() { void showVersion() {
cout << "CryFS Version " << version::VERSION_STRING << endl; cout << "CryFS Version " << version::VERSION_STRING << endl;