Introduce a buffer class that has its own allocator which makes sure
the buffer is 512 byte aligned. Open metadata devices with O_DIRECT to let us work with live metadata.
This commit is contained in:
parent
e25c211591
commit
2598648e62
67
block.h
67
block.h
@ -30,6 +30,7 @@
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
@ -39,12 +40,47 @@ namespace persistent_data {
|
||||
|
||||
typedef uint64_t block_address;
|
||||
|
||||
template <uint32_t BlockSize>
|
||||
template <uint32_t BlockSize = MD_BLOCK_SIZE, uint32_t Alignment = 512>
|
||||
class buffer : private boost::noncopyable {
|
||||
public:
|
||||
unsigned char &operator[](unsigned index) {
|
||||
if (index >= BlockSize)
|
||||
throw std::runtime_error("buffer index out of bounds");
|
||||
|
||||
return data_[index];
|
||||
}
|
||||
|
||||
unsigned char const &operator[](unsigned index) const {
|
||||
if (index >= BlockSize)
|
||||
throw std::runtime_error("buffer index out of bounds");
|
||||
|
||||
return data_[index];
|
||||
}
|
||||
|
||||
unsigned char *raw() {
|
||||
return data_;
|
||||
}
|
||||
|
||||
unsigned char const *raw() const {
|
||||
return data_;
|
||||
}
|
||||
|
||||
static void *operator new(size_t s) {
|
||||
return ::memalign(Alignment, s);
|
||||
}
|
||||
|
||||
static void operator delete(void *p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char data_[BlockSize];
|
||||
};
|
||||
|
||||
template <uint32_t BlockSize = MD_BLOCK_SIZE>
|
||||
class block_io : private boost::noncopyable {
|
||||
public:
|
||||
typedef boost::shared_ptr<block_io> ptr;
|
||||
typedef unsigned char buffer[BlockSize];
|
||||
typedef unsigned char const const_buffer[BlockSize];
|
||||
|
||||
block_io(std::string const &path, block_address nr_blocks, bool writeable = false);
|
||||
~block_io();
|
||||
@ -53,8 +89,8 @@ namespace persistent_data {
|
||||
return nr_blocks_;
|
||||
}
|
||||
|
||||
void read_buffer(block_address location, buffer &buf) const;
|
||||
void write_buffer(block_address location, const_buffer &buf);
|
||||
void read_buffer(block_address location, buffer<BlockSize> &buf) const;
|
||||
void write_buffer(block_address location, buffer<BlockSize> const &buf);
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
@ -72,23 +108,20 @@ namespace persistent_data {
|
||||
unsigned max_concurrent_locks,
|
||||
bool writeable = false);
|
||||
|
||||
typedef unsigned char buffer[BlockSize];
|
||||
typedef unsigned char const const_buffer[BlockSize];
|
||||
|
||||
class validator {
|
||||
public:
|
||||
typedef boost::shared_ptr<validator> ptr;
|
||||
|
||||
virtual ~validator() {}
|
||||
|
||||
virtual void check(const_buffer &b, block_address location) const = 0;
|
||||
virtual void prepare(buffer &b, block_address location) const = 0;
|
||||
virtual void check(buffer<BlockSize> const &b, block_address location) const = 0;
|
||||
virtual void prepare(buffer<BlockSize> &b, block_address location) const = 0;
|
||||
};
|
||||
|
||||
class noop_validator : public validator {
|
||||
public:
|
||||
void check(const_buffer &b, block_address location) const {}
|
||||
void prepare(buffer &b, block_address location) const {}
|
||||
void check(buffer<BlockSize> const &b, block_address location) const {}
|
||||
void prepare(buffer<BlockSize> &b, block_address location) const {}
|
||||
};
|
||||
|
||||
enum block_type {
|
||||
@ -96,7 +129,7 @@ namespace persistent_data {
|
||||
BT_NORMAL
|
||||
};
|
||||
|
||||
struct block {
|
||||
struct block : private boost::noncopyable {
|
||||
typedef boost::shared_ptr<block> ptr;
|
||||
|
||||
block(typename block_io<BlockSize>::ptr io,
|
||||
@ -118,12 +151,12 @@ namespace persistent_data {
|
||||
|
||||
typename block_io<BlockSize>::ptr io_;
|
||||
block_address location_;
|
||||
buffer data_;
|
||||
std::auto_ptr<buffer<BlockSize> > data_;
|
||||
typename validator::ptr validator_;
|
||||
block_type bt_;
|
||||
bool dirty_;
|
||||
};
|
||||
typedef typename block::ptr block_ptr;
|
||||
typedef typename block::ptr block_ptr; // FIXME: remove
|
||||
|
||||
class read_ref {
|
||||
public:
|
||||
@ -135,7 +168,7 @@ namespace persistent_data {
|
||||
read_ref const &operator =(read_ref const &rhs);
|
||||
|
||||
block_address get_location() const;
|
||||
const_buffer &data() const;
|
||||
buffer<BlockSize> const &data() const;
|
||||
|
||||
protected:
|
||||
block_manager<BlockSize> const &bm_;
|
||||
@ -151,7 +184,7 @@ namespace persistent_data {
|
||||
typename block::ptr b);
|
||||
|
||||
using read_ref::data;
|
||||
buffer &data();
|
||||
buffer<BlockSize> &data();
|
||||
};
|
||||
|
||||
// Locking methods
|
||||
|
33
block.tcc
33
block.tcc
@ -40,7 +40,7 @@ block_io<BlockSize>::block_io(std::string const &path, block_address nr_blocks,
|
||||
writeable_(writeable)
|
||||
{
|
||||
// fd_ = ::open(path.c_str(), writeable ? (O_RDWR | O_CREAT) : O_RDONLY, 0666);
|
||||
fd_ = ::open(path.c_str(), writeable ? O_RDWR : O_RDONLY, 0666);
|
||||
fd_ = ::open(path.c_str(), O_DIRECT | O_SYNC | (writeable ? O_RDWR : O_RDONLY), 0666);
|
||||
if (fd_ < 0)
|
||||
throw std::runtime_error("couldn't open file");
|
||||
}
|
||||
@ -53,7 +53,7 @@ block_io<BlockSize>::~block_io()
|
||||
|
||||
template <uint32_t BlockSize>
|
||||
void
|
||||
block_io<BlockSize>::read_buffer(block_address location, buffer &buffer) const
|
||||
block_io<BlockSize>::read_buffer(block_address location, buffer<BlockSize> &buffer) const
|
||||
{
|
||||
off_t r;
|
||||
r = ::lseek(fd_, BlockSize * location, SEEK_SET);
|
||||
@ -62,7 +62,7 @@ block_io<BlockSize>::read_buffer(block_address location, buffer &buffer) const
|
||||
|
||||
ssize_t n;
|
||||
size_t remaining = BlockSize;
|
||||
unsigned char *buf = buffer;
|
||||
unsigned char *buf = buffer.raw();
|
||||
do {
|
||||
n = ::read(fd_, buf, remaining);
|
||||
if (n > 0) {
|
||||
@ -77,7 +77,7 @@ block_io<BlockSize>::read_buffer(block_address location, buffer &buffer) const
|
||||
|
||||
template <uint32_t BlockSize>
|
||||
void
|
||||
block_io<BlockSize>::write_buffer(block_address location, const_buffer &buffer)
|
||||
block_io<BlockSize>::write_buffer(block_address location, buffer<BlockSize> const &buffer)
|
||||
{
|
||||
off_t r;
|
||||
r = ::lseek(fd_, BlockSize * location, SEEK_SET);
|
||||
@ -86,7 +86,7 @@ block_io<BlockSize>::write_buffer(block_address location, const_buffer &buffer)
|
||||
|
||||
ssize_t n;
|
||||
size_t remaining = BlockSize;
|
||||
unsigned char const *buf = buffer;
|
||||
unsigned char const *buf = buffer.raw();
|
||||
do {
|
||||
n = ::write(fd_, buf, remaining);
|
||||
if (n > 0) {
|
||||
@ -118,16 +118,17 @@ block_manager<BlockSize>::block::block(typename block_io<BlockSize>::ptr io,
|
||||
bool zero)
|
||||
: io_(io),
|
||||
location_(location),
|
||||
data_(new buffer<BlockSize>()),
|
||||
validator_(v),
|
||||
bt_(bt),
|
||||
dirty_(false)
|
||||
{
|
||||
if (zero) {
|
||||
memset(&data_, 0, sizeof(data_));
|
||||
memset(data_->raw(), 0, BlockSize);
|
||||
dirty_ = true;
|
||||
} else {
|
||||
io_->read_buffer(location_, data_);
|
||||
validator_->check(data_, location_);
|
||||
io_->read_buffer(location_, *data_);
|
||||
validator_->check(*data_, location_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,8 +143,8 @@ void
|
||||
block_manager<BlockSize>::block::flush()
|
||||
{
|
||||
if (dirty_) {
|
||||
validator_->prepare(data_, location_);
|
||||
io_->write_buffer(location_, data_);
|
||||
validator_->prepare(*data_, location_);
|
||||
io_->write_buffer(location_, *data_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,10 +204,10 @@ block_manager<BlockSize>::read_ref::get_location() const
|
||||
}
|
||||
|
||||
template <uint32_t BlockSize>
|
||||
typename block_manager<BlockSize>::const_buffer &
|
||||
buffer<BlockSize> const &
|
||||
block_manager<BlockSize>::read_ref::data() const
|
||||
{
|
||||
return block_->data_;
|
||||
return *block_->data_;
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
@ -220,10 +221,10 @@ block_manager<BlockSize>::write_ref::write_ref(block_manager<BlockSize> const &b
|
||||
}
|
||||
|
||||
template <uint32_t BlockSize>
|
||||
typename block_manager<BlockSize>::buffer &
|
||||
buffer<BlockSize> &
|
||||
block_manager<BlockSize>::write_ref::data()
|
||||
{
|
||||
return read_ref::block_->data_;
|
||||
return *read_ref::block_->data_;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
@ -285,7 +286,7 @@ block_manager<BlockSize>::write_lock_zero(block_address location,
|
||||
boost::optional<block_ptr> cached_block = cache_.get(location);
|
||||
if (cached_block) {
|
||||
(*cached_block)->check_write_lockable();
|
||||
memset(&(*cached_block)->data_, 0, BlockSize);
|
||||
memset((*cached_block)->data_->raw(), 0, BlockSize);
|
||||
return write_ref(*this, *cached_block);
|
||||
}
|
||||
|
||||
@ -326,7 +327,7 @@ block_manager<BlockSize>::superblock_zero(block_address location,
|
||||
|
||||
if (cached_block) {
|
||||
(*cached_block)->check_write_lockable();
|
||||
memset(&(*cached_block)->data_, 0, BlockSize);
|
||||
memset((*cached_block)->data_->raw(), 0, BlockSize); // FIXME: add a zero method to buffer
|
||||
(*cached_block)->validator_ = v;
|
||||
return write_ref(*this, *cached_block);
|
||||
}
|
||||
|
4
btree.h
4
btree.h
@ -176,7 +176,7 @@ namespace persistent_data {
|
||||
return node_ref<ValueTraits>(
|
||||
b.get_location(),
|
||||
reinterpret_cast<disk_node *>(
|
||||
const_cast<unsigned char *>(b.data())));
|
||||
const_cast<unsigned char *>(b.data().raw())));
|
||||
}
|
||||
|
||||
template <typename ValueTraits>
|
||||
@ -186,7 +186,7 @@ namespace persistent_data {
|
||||
return node_ref<ValueTraits>(
|
||||
b.get_location(),
|
||||
reinterpret_cast<disk_node *>(
|
||||
const_cast<unsigned char *>(b.data())));
|
||||
const_cast<unsigned char *>(b.data().raw())));
|
||||
}
|
||||
|
||||
class ro_spine : private noncopyable {
|
||||
|
@ -33,7 +33,7 @@ using namespace std;
|
||||
|
||||
namespace {
|
||||
struct btree_node_validator : public block_manager<>::validator {
|
||||
virtual void check(block_manager<>::const_buffer &b, block_address location) const {
|
||||
virtual void check(buffer<> const &b, block_address location) const {
|
||||
disk_node const *data = reinterpret_cast<disk_node const *>(&b);
|
||||
node_header const *n = &data->header;
|
||||
crc32c sum(BTREE_CSUM_XOR);
|
||||
@ -45,7 +45,7 @@ namespace {
|
||||
throw checksum_error("bad block nr in btree node");
|
||||
}
|
||||
|
||||
virtual void prepare(block_manager<>::buffer &b, block_address location) const {
|
||||
virtual void prepare(buffer<> &b, block_address location) const {
|
||||
disk_node *data = reinterpret_cast<disk_node *>(&b);
|
||||
node_header *n = &data->header;
|
||||
n->blocknr = to_disk<base::__le64, uint64_t>(location);
|
||||
|
14
metadata.cc
14
metadata.cc
@ -40,7 +40,7 @@ namespace {
|
||||
uint32_t const SUPERBLOCK_CSUM_SEED = 160774;
|
||||
|
||||
struct superblock_validator : public block_manager<>::validator {
|
||||
virtual void check(block_manager<>::const_buffer &b, block_address location) const {
|
||||
virtual void check(buffer<> const &b, block_address location) const {
|
||||
superblock_disk const *sbd = reinterpret_cast<superblock_disk const *>(&b);
|
||||
crc32c sum(SUPERBLOCK_CSUM_SEED);
|
||||
sum.append(&sbd->flags_, MD_BLOCK_SIZE - sizeof(uint32_t));
|
||||
@ -48,7 +48,7 @@ namespace {
|
||||
throw checksum_error("bad checksum in superblock");
|
||||
}
|
||||
|
||||
virtual void prepare(block_manager<>::buffer &b, block_address location) const {
|
||||
virtual void prepare(buffer<> &b, block_address location) const {
|
||||
superblock_disk *sbd = reinterpret_cast<superblock_disk *>(&b);
|
||||
crc32c sum(SUPERBLOCK_CSUM_SEED);
|
||||
sum.append(&sbd->flags_, MD_BLOCK_SIZE - sizeof(uint32_t));
|
||||
@ -127,6 +127,10 @@ metadata::metadata(std::string const &dev_path, open_type ot,
|
||||
case OPEN:
|
||||
tm_ = open_tm(dev_path, false);
|
||||
sb_ = read_superblock(tm_->get_bm());
|
||||
|
||||
if (sb_.version_ != 1)
|
||||
throw runtime_error("unknown metadata version");
|
||||
|
||||
metadata_sm_ = open_metadata_sm(tm_, &sb_.metadata_space_map_root_);
|
||||
tm_->set_sm(metadata_sm_);
|
||||
|
||||
@ -161,10 +165,10 @@ metadata::metadata(std::string const &dev_path, open_type ot,
|
||||
}
|
||||
}
|
||||
|
||||
metadata::metadata(std::string const &dev_path, block_address held_root)
|
||||
metadata::metadata(std::string const &dev_path, block_address metadata_snap)
|
||||
{
|
||||
tm_ = open_tm(dev_path, false);
|
||||
sb_ = read_superblock(tm_->get_bm(), held_root);
|
||||
sb_ = read_superblock(tm_->get_bm(), metadata_snap);
|
||||
// We don't open the metadata sm for a held root
|
||||
//metadata_sm_ = open_metadata_sm(tm_, &sb_.metadata_space_map_root_);
|
||||
tm_->set_sm(metadata_sm_);
|
||||
@ -208,7 +212,7 @@ metadata::commit()
|
||||
superblock_validator v;
|
||||
write_ref superblock = tm_->get_bm()->superblock_zero(SUPERBLOCK_LOCATION,
|
||||
mk_validator(new superblock_validator()));
|
||||
superblock_disk *disk = reinterpret_cast<superblock_disk *>(superblock.data());
|
||||
superblock_disk *disk = reinterpret_cast<superblock_disk *>(superblock.data().raw());
|
||||
superblock_traits::pack(sb_, *disk);
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ namespace thin_provisioning {
|
||||
sector_t data_block_size = 128,
|
||||
block_address nr_data_blocks = 0); // Only used if CREATE
|
||||
|
||||
metadata(std::string const &dev_path, block_address held_root);
|
||||
metadata(std::string const &dev_path, block_address metadata_snap);
|
||||
|
||||
void commit();
|
||||
|
||||
|
@ -171,11 +171,11 @@ thin_provisioning::metadata_check(metadata::ptr md)
|
||||
|
||||
block_counter metadata_counter, data_counter;
|
||||
|
||||
if (md->sb_.held_root_) {
|
||||
if (md->sb_.metadata_snap_) {
|
||||
block_manager<>::ptr bm = md->tm_->get_bm();
|
||||
|
||||
|
||||
block_address root = md->sb_.held_root_;
|
||||
block_address root = md->sb_.metadata_snap_;
|
||||
|
||||
metadata_counter.inc(root);
|
||||
|
||||
|
@ -55,7 +55,7 @@ superblock_traits::unpack(superblock_disk const &disk, superblock &value)
|
||||
value.time_ = to_cpu<uint32_t>(disk.time_);
|
||||
|
||||
value.trans_id_ = to_cpu<uint64_t>(disk.trans_id_);
|
||||
value.held_root_ = to_cpu<uint64_t>(disk.held_root_);
|
||||
value.metadata_snap_ = to_cpu<uint64_t>(disk.metadata_snap_);
|
||||
|
||||
::memcpy(value.data_space_map_root_,
|
||||
disk.data_space_map_root_,
|
||||
@ -88,7 +88,7 @@ superblock_traits::pack(superblock const &value, superblock_disk &disk)
|
||||
disk.time_ = to_disk<__le32>(value.time_);
|
||||
|
||||
disk.trans_id_ = to_disk<__le64>(value.trans_id_);
|
||||
disk.held_root_ = to_disk<__le64>(value.held_root_);
|
||||
disk.metadata_snap_ = to_disk<__le64>(value.metadata_snap_);
|
||||
|
||||
::memcpy(disk.data_space_map_root_,
|
||||
value.data_space_map_root_,
|
||||
|
@ -66,7 +66,7 @@ namespace thin_provisioning {
|
||||
|
||||
__le64 trans_id_;
|
||||
/* root for userspace's transaction (for migration and friends) */
|
||||
__le64 held_root_;
|
||||
__le64 metadata_snap_;
|
||||
|
||||
__u8 data_space_map_root_[SPACE_MAP_ROOT_SIZE];
|
||||
__u8 metadata_space_map_root_[SPACE_MAP_ROOT_SIZE];
|
||||
@ -99,7 +99,7 @@ namespace thin_provisioning {
|
||||
|
||||
uint64_t trans_id_;
|
||||
/* root for userspace's transaction (for migration and friends) */
|
||||
uint64_t held_root_;
|
||||
uint64_t metadata_snap_;
|
||||
|
||||
unsigned char data_space_map_root_[SPACE_MAP_ROOT_SIZE];
|
||||
unsigned char metadata_space_map_root_[SPACE_MAP_ROOT_SIZE];
|
||||
|
@ -186,10 +186,15 @@ namespace {
|
||||
void
|
||||
thin_provisioning::metadata_dump(metadata::ptr md, emitter::ptr e, bool repair)
|
||||
{
|
||||
optional<uint64_t> md_snap = md->sb_.metadata_snap_ ?
|
||||
optional<uint64_t>(md->sb_.metadata_snap_) :
|
||||
optional<uint64_t>();
|
||||
|
||||
e->begin_superblock("", md->sb_.time_,
|
||||
md->sb_.trans_id_,
|
||||
md->sb_.data_block_size_,
|
||||
md->data_sm_->get_nr_blocks());
|
||||
md->data_sm_->get_nr_blocks(),
|
||||
md_snap);
|
||||
|
||||
details_extractor::ptr de(new details_extractor);
|
||||
|
||||
|
@ -38,7 +38,7 @@ namespace {
|
||||
uint64_t const BITMAP_CSUM_XOR = 240779;
|
||||
|
||||
struct bitmap_block_validator : public block_manager<>::validator {
|
||||
virtual void check(block_manager<>::const_buffer &b, block_address location) const {
|
||||
virtual void check(buffer<> const &b, block_address location) const {
|
||||
bitmap_header const *data = reinterpret_cast<bitmap_header const *>(&b);
|
||||
crc32c sum(BITMAP_CSUM_XOR);
|
||||
sum.append(&data->not_used, MD_BLOCK_SIZE - sizeof(uint32_t));
|
||||
@ -49,7 +49,7 @@ namespace {
|
||||
throw checksum_error("bad block nr in space map bitmap");
|
||||
}
|
||||
|
||||
virtual void prepare(block_manager<>::buffer &b, block_address location) const {
|
||||
virtual void prepare(buffer<> &b, block_address location) const {
|
||||
bitmap_header *data = reinterpret_cast<bitmap_header *>(&b);
|
||||
data->blocknr = to_disk<base::__le64, uint64_t>(location);
|
||||
|
||||
@ -70,7 +70,7 @@ namespace {
|
||||
|
||||
// FIXME: factor out the common code in these validators
|
||||
struct index_block_validator : public block_manager<>::validator {
|
||||
virtual void check(block_manager<>::const_buffer &b, block_address location) const {
|
||||
virtual void check(buffer<> const &b, block_address location) const {
|
||||
metadata_index const *mi = reinterpret_cast<metadata_index const *>(&b);
|
||||
crc32c sum(INDEX_CSUM_XOR);
|
||||
sum.append(&mi->padding_, MD_BLOCK_SIZE - sizeof(uint32_t));
|
||||
@ -81,7 +81,7 @@ namespace {
|
||||
throw checksum_error("bad block nr in metadata index block");
|
||||
}
|
||||
|
||||
virtual void prepare(block_manager<>::buffer &b, block_address location) const {
|
||||
virtual void prepare(buffer<> &b, block_address location) const {
|
||||
metadata_index *mi = reinterpret_cast<metadata_index *>(&b);
|
||||
mi->blocknr_ = to_disk<base::__le64, uint64_t>(location);
|
||||
|
||||
|
@ -193,7 +193,7 @@ namespace {
|
||||
field(f, "version", sb.version_);
|
||||
field(f, "time", sb.time_);
|
||||
field(f, "trans id", sb.trans_id_);
|
||||
field(f, "held root", sb.held_root_);
|
||||
field(f, "metadata snap", sb.metadata_snap_);
|
||||
field(f, "data mapping root", sb.data_mapping_root_);
|
||||
field(f, "device details root", sb.device_details_root_);
|
||||
field(f, "data block size", sb.data_block_size_);
|
||||
|
@ -73,7 +73,7 @@ transaction_manager::shadow(block_address orig, validator v)
|
||||
throw runtime_error("couldn't allocate new block");
|
||||
|
||||
write_ref dest = bm_->write_lock_zero(*mb, v);
|
||||
::memcpy(dest.data(), src.data(), MD_BLOCK_SIZE);
|
||||
::memcpy(dest.data().raw(), src.data().raw(), MD_BLOCK_SIZE); // FIXME: use buffer copy method
|
||||
|
||||
ref_t count = sm_->get_count(orig);
|
||||
if (count == 0)
|
||||
|
Loading…
Reference in New Issue
Block a user