mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
bcache-utils: rewrite
They take care to avoid redundant reads now.
This commit is contained in:
parent
2688aafefb
commit
dfc320f5b8
@ -29,6 +29,16 @@ static void byte_range_to_block_range(struct bcache *cache, uint64_t start, size
|
|||||||
*be = (start + len + block_size - 1) / block_size;
|
*be = (start + len + block_size - 1) / block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t _min(uint64_t lhs, uint64_t rhs)
|
||||||
|
{
|
||||||
|
if (rhs < lhs)
|
||||||
|
return rhs;
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
void bcache_prefetch_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
void bcache_prefetch_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
||||||
{
|
{
|
||||||
block_address bb, be;
|
block_address bb, be;
|
||||||
@ -40,119 +50,55 @@ void bcache_prefetch_bytes(struct bcache *cache, int fd, uint64_t start, size_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t _min(uint64_t lhs, uint64_t rhs)
|
//----------------------------------------------------------------
|
||||||
{
|
|
||||||
if (rhs < lhs)
|
|
||||||
return rhs;
|
|
||||||
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: there's common code that can be factored out of these 3
|
|
||||||
bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data)
|
bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data)
|
||||||
{
|
{
|
||||||
struct block *b;
|
struct block *b;
|
||||||
block_address bb, be, i;
|
block_address bb, be;
|
||||||
unsigned char *udata = data;
|
|
||||||
uint64_t block_size = bcache_block_sectors(cache) << SECTOR_SHIFT;
|
uint64_t block_size = bcache_block_sectors(cache) << SECTOR_SHIFT;
|
||||||
int errors = 0;
|
uint64_t block_offset = start % block_size;
|
||||||
|
|
||||||
|
bcache_prefetch_bytes(cache, fd, start, len);
|
||||||
|
|
||||||
byte_range_to_block_range(cache, start, len, &bb, &be);
|
byte_range_to_block_range(cache, start, len, &bb, &be);
|
||||||
for (i = bb; i < be; i++)
|
|
||||||
bcache_prefetch(cache, fd, i);
|
|
||||||
|
|
||||||
for (i = bb; i < be; i++) {
|
for (; bb != be; bb++) {
|
||||||
if (!bcache_get(cache, fd, i, 0, &b, NULL)) {
|
if (!bcache_get(cache, fd, bb, 0, &b, NULL))
|
||||||
errors++;
|
return false;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == bb) {
|
|
||||||
uint64_t block_offset = start % block_size;
|
|
||||||
size_t blen = _min(block_size - block_offset, len);
|
size_t blen = _min(block_size - block_offset, len);
|
||||||
memcpy(udata, ((unsigned char *) b->data) + block_offset, blen);
|
memcpy(data, ((unsigned char *) b->data) + block_offset, blen);
|
||||||
len -= blen;
|
|
||||||
udata += blen;
|
|
||||||
} else {
|
|
||||||
size_t blen = _min(block_size, len);
|
|
||||||
memcpy(udata, b->data, blen);
|
|
||||||
len -= blen;
|
|
||||||
udata += blen;
|
|
||||||
}
|
|
||||||
|
|
||||||
bcache_put(b);
|
bcache_put(b);
|
||||||
}
|
|
||||||
|
|
||||||
return errors ? false : true;
|
block_offset = 0;
|
||||||
}
|
|
||||||
|
|
||||||
bool bcache_write_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data)
|
|
||||||
{
|
|
||||||
struct block *b;
|
|
||||||
block_address bb, be, i;
|
|
||||||
unsigned char *udata = data;
|
|
||||||
uint64_t block_size = bcache_block_sectors(cache) << SECTOR_SHIFT;
|
|
||||||
int errors = 0;
|
|
||||||
|
|
||||||
byte_range_to_block_range(cache, start, len, &bb, &be);
|
|
||||||
for (i = bb; i < be; i++)
|
|
||||||
bcache_prefetch(cache, fd, i);
|
|
||||||
|
|
||||||
for (i = bb; i < be; i++) {
|
|
||||||
if (!bcache_get(cache, fd, i, GF_DIRTY, &b, NULL)) {
|
|
||||||
errors++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == bb) {
|
|
||||||
uint64_t block_offset = start % block_size;
|
|
||||||
size_t blen = _min(block_size - block_offset, len);
|
|
||||||
memcpy(((unsigned char *) b->data) + block_offset, udata, blen);
|
|
||||||
len -= blen;
|
len -= blen;
|
||||||
udata += blen;
|
data = ((unsigned char *) data) + blen;
|
||||||
} else {
|
|
||||||
size_t blen = _min(block_size, len);
|
|
||||||
memcpy(b->data, udata, blen);
|
|
||||||
len -= blen;
|
|
||||||
udata += blen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bcache_put(b);
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return errors ? false : true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
static bool _zero_whole_blocks(struct bcache *cache, int fd, block_address bb, block_address be)
|
// Writing bytes and zeroing bytes are very similar, so we factor out
|
||||||
{
|
// this common code.
|
||||||
struct block *b;
|
|
||||||
|
struct updater;
|
||||||
for (; bb != be; bb++) {
|
|
||||||
if (!bcache_get(cache, fd, bb, GF_ZERO, &b, NULL))
|
typedef bool (*partial_update_fn)(struct updater *u, int fd, block_address bb, uint64_t offset, size_t len);
|
||||||
return false;
|
typedef bool (*whole_update_fn)(struct updater *u, int fd, block_address bb, block_address be);
|
||||||
bcache_put(b);
|
|
||||||
}
|
struct updater {
|
||||||
|
struct bcache *cache;
|
||||||
return true;
|
partial_update_fn partial_fn;
|
||||||
}
|
whole_update_fn whole_fn;
|
||||||
|
void *data;
|
||||||
static bool _zero_partial(struct bcache *cache, int fd, block_address bb, uint64_t offset, size_t len)
|
};
|
||||||
{
|
|
||||||
struct block *b;
|
static bool _update_bytes(struct updater *u, int fd, uint64_t start, size_t len)
|
||||||
|
|
||||||
if (!bcache_get(cache, fd, bb, GF_DIRTY, &b, NULL))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
memset(((unsigned char *) b->data) + offset, 0, len);
|
|
||||||
bcache_put(b);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
|
||||||
{
|
{
|
||||||
|
struct bcache *cache = u->cache;
|
||||||
block_address bb, be;
|
block_address bb, be;
|
||||||
uint64_t block_size = bcache_block_sectors(cache) << SECTOR_SHIFT;
|
uint64_t block_size = bcache_block_sectors(cache) << SECTOR_SHIFT;
|
||||||
uint64_t block_offset = start % block_size;
|
uint64_t block_offset = start % block_size;
|
||||||
@ -160,10 +106,15 @@ bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
|||||||
|
|
||||||
byte_range_to_block_range(cache, start, len, &bb, &be);
|
byte_range_to_block_range(cache, start, len, &bb, &be);
|
||||||
|
|
||||||
|
// If the last block is partial, we will require a read, so let's
|
||||||
|
// prefetch it.
|
||||||
|
if ((start + len) % block_size)
|
||||||
|
bcache_prefetch(cache, fd, (start + len) / block_size);
|
||||||
|
|
||||||
// First block may be partial
|
// First block may be partial
|
||||||
if (block_offset) {
|
if (block_offset) {
|
||||||
size_t blen = _min(block_size - block_offset, len);
|
size_t blen = _min(block_size - block_offset, len);
|
||||||
if (!_zero_partial(cache, fd, bb, block_offset, blen))
|
if (!u->partial_fn(u, fd, bb, block_offset, blen))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
len -= blen;
|
len -= blen;
|
||||||
@ -175,8 +126,9 @@ bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
|||||||
|
|
||||||
// Now we write out a set of whole blocks
|
// Now we write out a set of whole blocks
|
||||||
nr_whole = len / block_size;
|
nr_whole = len / block_size;
|
||||||
if (!_zero_whole_blocks(cache, fd, bb, bb + nr_whole))
|
if (!u->whole_fn(u, fd, bb, bb + nr_whole))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bb += nr_whole;
|
bb += nr_whole;
|
||||||
len -= nr_whole * block_size;
|
len -= nr_whole * block_size;
|
||||||
|
|
||||||
@ -184,7 +136,94 @@ bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Finally we write a partial end block
|
// Finally we write a partial end block
|
||||||
return _zero_partial(cache, fd, bb, 0, len);
|
return u->partial_fn(u, fd, bb, 0, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
static bool _write_partial(struct updater *u, int fd, block_address bb,
|
||||||
|
uint64_t offset, size_t len)
|
||||||
|
{
|
||||||
|
struct block *b;
|
||||||
|
|
||||||
|
if (!bcache_get(u->cache, fd, bb, GF_DIRTY, &b, NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(((unsigned char *) b->data) + offset, u->data, len);
|
||||||
|
u->data = ((unsigned char *) u->data) + len;
|
||||||
|
|
||||||
|
bcache_put(b);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _write_whole(struct updater *u, int fd, block_address bb, block_address be)
|
||||||
|
{
|
||||||
|
struct block *b;
|
||||||
|
uint64_t block_size = bcache_block_sectors(u->cache) << SECTOR_SHIFT;
|
||||||
|
|
||||||
|
for (; bb != be; bb++) {
|
||||||
|
// We don't need to read the block since we are overwriting
|
||||||
|
// it completely.
|
||||||
|
if (!bcache_get(u->cache, fd, bb, GF_ZERO, &b, NULL))
|
||||||
|
return false;
|
||||||
|
memcpy(b->data, u->data, block_size);
|
||||||
|
u->data = ((unsigned char *) u->data) + block_size;
|
||||||
|
bcache_put(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bcache_write_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data)
|
||||||
|
{
|
||||||
|
struct updater u;
|
||||||
|
|
||||||
|
u.cache = cache;
|
||||||
|
u.partial_fn = _write_partial;
|
||||||
|
u.whole_fn = _write_whole;
|
||||||
|
u.data = data;
|
||||||
|
|
||||||
|
return _update_bytes(&u, fd, start, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
static bool _zero_partial(struct updater *u, int fd, block_address bb, uint64_t offset, size_t len)
|
||||||
|
{
|
||||||
|
struct block *b;
|
||||||
|
|
||||||
|
if (!bcache_get(u->cache, fd, bb, GF_DIRTY, &b, NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memset(((unsigned char *) b->data) + offset, 0, len);
|
||||||
|
bcache_put(b);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _zero_whole(struct updater *u, int fd, block_address bb, block_address be)
|
||||||
|
{
|
||||||
|
struct block *b;
|
||||||
|
|
||||||
|
for (; bb != be; bb++) {
|
||||||
|
if (!bcache_get(u->cache, fd, bb, GF_ZERO, &b, NULL))
|
||||||
|
return false;
|
||||||
|
bcache_put(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
||||||
|
{
|
||||||
|
struct updater u;
|
||||||
|
|
||||||
|
u.cache = cache;
|
||||||
|
u.partial_fn = _zero_partial;
|
||||||
|
u.whole_fn = _zero_whole;
|
||||||
|
u.data = NULL;
|
||||||
|
|
||||||
|
return _update_bytes(&u, fd, start, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user