master - scan: invalidate bcache for dev after errors
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=da2b155a9da4c4c9caf...
Commit: da2b155a9da4c4c9caf502b87ad263de6e678b30
Parent: 4331182964e37ad75690007f5f874f2606944a34
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Feb 27 15:03:56 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:47 2018 -0500
scan: invalidate bcache for dev after errors
If there are errors reading or writing dev,
invalidate bcache for it.
---
lib/label/label.c | 25 +++++++++++++++++++------
1 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/lib/label/label.c b/lib/label/label.c
index 88001a9..0514ddf 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -871,11 +871,16 @@ bool dev_read_bytes(struct device *dev, off_t start, size_t len, void *data)
}
if (dev->bcache_fd <= 0) {
- log_error("dev_read_bytes %s with invalid bcache_fd", dev_name(dev));
+ log_error("dev_read_bytes %s with invalid fd %d", dev_name(dev), dev->bcache_fd);
return false;
}
- return bcache_read_bytes(scan_bcache, dev->bcache_fd, start, len, data);
+ if (!bcache_read_bytes(scan_bcache, dev->bcache_fd, start, len, data)) {
+ label_scan_invalidate(dev);
+ return false;
+ }
+ return true;
+
}
bool dev_write_bytes(struct device *dev, off_t start, size_t len, void *data)
@@ -895,11 +900,15 @@ bool dev_write_bytes(struct device *dev, off_t start, size_t len, void *data)
}
if (dev->bcache_fd <= 0) {
- log_error("dev_write_bytes %s with invalid bcache_fd", dev_name(dev));
+ log_error("dev_write_bytes %s with invalid fd %d", dev_name(dev), dev->bcache_fd);
return false;
}
- return bcache_write_bytes(scan_bcache, dev->bcache_fd, start, len, data);
+ if (!bcache_write_bytes(scan_bcache, dev->bcache_fd, start, len, data)) {
+ label_scan_invalidate(dev);
+ return false;
+ }
+ return true;
}
bool dev_write_zeros(struct device *dev, off_t start, size_t len)
@@ -919,10 +928,14 @@ bool dev_write_zeros(struct device *dev, off_t start, size_t len)
}
if (dev->bcache_fd <= 0) {
- log_error("dev_write_bytes %s with invalid bcache_fd", dev_name(dev));
+ log_error("dev_write_bytes %s with invalid fd %d", dev_name(dev), dev->bcache_fd);
return false;
}
- return bcache_write_zeros(scan_bcache, dev->bcache_fd, start, len);
+ if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, start, len)) {
+ label_scan_invalidate(dev);
+ return false;
+ }
+ return true;
}
6 years
master - [device/bcache] fix bug in _alloc_block
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=19647d1cd44d029a8aa...
Commit: 19647d1cd44d029a8aa2f7e74dbdbd1f114a8c08
Parent: 1563b936911d26c665b590f200884c9ed31ab7c3
Author: Joe Thornber <ejt(a)redhat.com>
AuthorDate: Fri Feb 2 14:34:45 2018 +0000
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:12:50 2018 -0500
[device/bcache] fix bug in _alloc_block
---
lib/device/bcache.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 4283ce5..e5d0e1b 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -449,8 +449,10 @@ static void _exit_free_list(struct bcache *cache)
static struct block *_alloc_block(struct bcache *cache)
{
- struct block *b = dm_list_struct_base(_list_pop(&cache->free), struct block, list);
- return b;
+ if (dm_list_empty(&cache->free))
+ return NULL;
+
+ return dm_list_struct_base(_list_pop(&cache->free), struct block, list);
}
/*----------------------------------------------------------------
6 years
master - [device/bcache] Add bcache_max_prefetches()
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=1563b936911d26c665b...
Commit: 1563b936911d26c665b590f200884c9ed31ab7c3
Parent: c4c4acfd423323cbe8fbfbdb8c1882edb4a92b29
Author: Joe Thornber <ejt(a)redhat.com>
AuthorDate: Fri Feb 2 12:06:14 2018 +0000
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:12:50 2018 -0500
[device/bcache] Add bcache_max_prefetches()
Ignore prefetches if max io is in flight.
---
lib/device/bcache.c | 23 +++++++++++++++--------
lib/device/bcache.h | 1 +
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 09ef6ef..4283ce5 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -216,17 +216,18 @@ static bool _engine_issue(struct io_engine *e, enum dir d, int fd,
return true;
}
-#define MAX_IO 64
+#define MAX_IO 1024
+#define MAX_EVENT 64
typedef void complete_fn(void *context, int io_error);
static bool _engine_wait(struct io_engine *e, complete_fn fn)
{
int i, r;
- struct io_event event[MAX_IO];
+ struct io_event event[MAX_EVENT];
struct control_block *cb;
memset(&event, 0, sizeof(event));
- r = io_getevents(e->aio_context, 1, MAX_IO, event, NULL);
+ r = io_getevents(e->aio_context, 1, MAX_EVENT, event, NULL);
if (r < 0) {
log_sys_warn("io_getevents");
return false;
@@ -300,6 +301,7 @@ struct bcache {
sector_t block_sectors;
uint64_t nr_data_blocks;
uint64_t nr_cache_blocks;
+ unsigned max_io;
struct io_engine *engine;
@@ -762,8 +764,8 @@ struct bcache *bcache_create(sector_t block_sectors, unsigned nr_cache_blocks)
cache->block_sectors = block_sectors;
cache->nr_cache_blocks = nr_cache_blocks;
-
- cache->engine = _engine_create(nr_cache_blocks < 1024u ? nr_cache_blocks : 1024u);
+ cache->max_io = nr_cache_blocks < MAX_IO ? nr_cache_blocks : MAX_IO;
+ cache->engine = _engine_create(cache->max_io);
if (!cache->engine) {
dm_free(cache);
return NULL;
@@ -820,16 +822,21 @@ unsigned bcache_nr_cache_blocks(struct bcache *cache)
return cache->nr_cache_blocks;
}
+unsigned bcache_max_prefetches(struct bcache *cache)
+{
+ return cache->max_io;
+}
+
void bcache_prefetch(struct bcache *cache, int fd, block_address index)
{
struct block *b = _hash_lookup(cache, fd, index);
if (!b) {
- cache->prefetches++;
-
b = _new_block(cache, fd, index);
- if (b)
+ if (b && (cache->nr_io_pending < cache->max_io)) {
+ cache->prefetches++;
_issue_read(b);
+ }
}
}
diff --git a/lib/device/bcache.h b/lib/device/bcache.h
index 5c68e3c..14204be 100644
--- a/lib/device/bcache.h
+++ b/lib/device/bcache.h
@@ -62,6 +62,7 @@ enum bcache_get_flags {
typedef uint64_t block_address;
unsigned bcache_nr_cache_blocks(struct bcache *cache);
+unsigned bcache_max_prefetches(struct bcache *cache);
/*
* Use the prefetch method to take advantage of asynchronous IO. For example,
6 years
master - bcache: add some error messages for debugging
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4331182964e37ad7569...
Commit: 4331182964e37ad75690007f5f874f2606944a34
Parent: 21057676a1f01c6b1f19b2e879d8385d76adb517
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Feb 27 12:37:25 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:47 2018 -0500
bcache: add some error messages for debugging
---
lib/device/bcache.c | 21 +++++++++++++++++++--
1 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 272de60..94623a8 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -659,8 +659,11 @@ static struct block *_new_block(struct bcache *cache, int fd, block_address inde
if (dm_list_empty(&cache->io_pending))
_writeback(cache, 16); // FIXME: magic number
_wait_io(cache);
- } else
+ } else {
+ log_error("bcache no new blocks for fd %d index %u",
+ fd, (uint32_t)index);
return NULL;
+ }
}
}
@@ -676,6 +679,18 @@ static struct block *_new_block(struct bcache *cache, int fd, block_address inde
_hash_insert(b);
}
+ if (!b) {
+ log_error("bcache no new blocks for fd %d index %u "
+ "clean %u free %u dirty %u pending %u nr_data_blocks %u nr_cache_blocks %u",
+ fd, (uint32_t)index,
+ dm_list_size(&cache->clean),
+ dm_list_size(&cache->free),
+ dm_list_size(&cache->dirty),
+ dm_list_size(&cache->io_pending),
+ (uint32_t)cache->nr_data_blocks,
+ (uint32_t)cache->nr_cache_blocks);
+ }
+
return b;
}
@@ -893,7 +908,7 @@ bool bcache_get(struct bcache *cache, int fd, block_address index,
}
*result = NULL;
- log_warn("couldn't get block");
+ log_error("bcache failed to get block %u fd %d", (uint32_t)index, fd);
return false;
}
@@ -1077,6 +1092,8 @@ bool bcache_write_bytes(struct bcache *cache, int fd, off_t start, size_t len, v
for (i = bb; i < be; i++) {
if (!bcache_get(cache, fd, i, 0, &b)) {
+ log_error("bcache_write failed to get block %u fd %d bb %u be %u",
+ (uint32_t)i, fd, (uint32_t)bb, (uint32_t)be);
errors++;
break;
}
6 years
master - [device/bcache] Add a couple of invalidate methods
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=c4c4acfd423323cbe8f...
Commit: c4c4acfd423323cbe8fbfbdb8c1882edb4a92b29
Parent: 0f0eb04edb00cb5e95c47cb9ca2e70574e6e49ce
Author: Joe Thornber <ejt(a)redhat.com>
AuthorDate: Fri Feb 2 07:59:49 2018 +0000
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:12:50 2018 -0500
[device/bcache] Add a couple of invalidate methods
---
lib/device/bcache.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib/device/bcache.h | 13 +++++++++++
2 files changed, 73 insertions(+), 0 deletions(-)
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 5a7b2f9..09ef6ef 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -884,5 +884,65 @@ int bcache_flush(struct bcache *cache)
return dm_list_empty(&cache->errored) ? 0 : -EIO;
}
+static void _recycle_block(struct bcache *cache, struct block *b)
+{
+ _unlink_block(b);
+ _hash_remove(b);
+ dm_list_add(&cache->free, &b->list);
+}
+
+/*
+ * You can safely call this with a NULL block.
+ */
+static void _invalidate_block(struct bcache *cache, struct block *b)
+{
+ if (!b)
+ return;
+
+ if (_test_flags(b, BF_IO_PENDING))
+ _wait_specific(b);
+
+ if (b->ref_count)
+ log_warn("bcache_invalidate: block (%d, %llu) still held",
+ b->fd, (unsigned long long) index);
+ else {
+ if (_test_flags(b, BF_DIRTY)) {
+ _issue_write(b);
+ _wait_specific(b);
+ }
+
+ _recycle_block(cache, b);
+ }
+}
+
+void bcache_invalidate(struct bcache *cache, int fd, block_address index)
+{
+ _invalidate_block(cache, _hash_lookup(cache, fd, index));
+}
+
+// FIXME: switch to a trie, or maybe 1 hash table per fd? To save iterating
+// through the whole cache.
+void bcache_invalidate_fd(struct bcache *cache, int fd)
+{
+ struct block *b, *tmp;
+
+ // Start writing back any dirty blocks on this fd.
+ dm_list_iterate_items_safe (b, tmp, &cache->dirty)
+ if (b->fd == fd)
+ _issue_write(b);
+
+ _wait_all(cache);
+
+ // Everything should be in the clean list now.
+ dm_list_iterate_items_safe (b, tmp, &cache->clean)
+ if (b->fd == fd)
+ _invalidate_block(cache, b);
+
+ // Except they could be in the errored list :)
+ dm_list_iterate_items_safe (b, tmp, &cache->errored)
+ if (b->fd == fd)
+ _recycle_block(cache, b);
+}
+
//----------------------------------------------------------------
diff --git a/lib/device/bcache.h b/lib/device/bcache.h
index 2730347..5c68e3c 100644
--- a/lib/device/bcache.h
+++ b/lib/device/bcache.h
@@ -93,6 +93,19 @@ void bcache_put(struct block *b);
int bcache_flush(struct bcache *cache);
+/*
+ * Removes a block from the cache. If the block is dirty it will be written
+ * back first. If the block is currently held a warning will be issued, and it
+ * will not be removed.
+ */
+void bcache_invalidate(struct bcache *cache, int fd, block_address index);
+
+/*
+ * Invalidates all blocks on the given descriptor. Call this before closing
+ * the descriptor to make sure everything is written back.
+ */
+void bcache_invalidate_fd(struct bcache *cache, int fd);
+
/*----------------------------------------------------------------*/
#endif
6 years
master - scan: create bcache with minimum number of blocks
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=21057676a1f01c6b1f1...
Commit: 21057676a1f01c6b1f19b2e879d8385d76adb517
Parent: e49b114f7e437666caefa04aada31f32820e286e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Feb 27 12:35:45 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:47 2018 -0500
scan: create bcache with minimum number of blocks
In some odd cases (e.g. tests) there are very few devices
which results in creating too few blocks in bcache, so
create bcache with a minimum number of blocks.
---
lib/label/label.c | 8 +++++---
1 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/lib/label/label.c b/lib/label/label.c
index 45a3ecf..88001a9 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -560,13 +560,15 @@ static int _scan_list(struct dm_list *devs, int *failed)
return 1;
}
+#define MIN_BCACHE_BLOCKS 32
+
static int _setup_bcache(int cache_blocks)
{
struct io_engine *ioe;
/* No devices can happen, just create bcache with any small number. */
- if (!cache_blocks)
- cache_blocks = 8;
+ if (cache_blocks < MIN_BCACHE_BLOCKS)
+ cache_blocks = MIN_BCACHE_BLOCKS;
/*
* 100 is arbitrary, it's the max number of concurrent aio's
@@ -831,7 +833,7 @@ int label_read_sector(struct device *dev, struct label **labelp, uint64_t scan_s
int label_scan_setup_bcache(void)
{
if (!scan_bcache) {
- if (!_setup_bcache(32))
+ if (!_setup_bcache(0))
return 0;
}
6 years
master - bcache: use wrappers for bcache read write in lvm
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=e49b114f7e437666cae...
Commit: e49b114f7e437666caefa04aada31f32820e286e
Parent: 80654920468841251a7f940e410ca61de8383b41
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Feb 27 11:26:04 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:47 2018 -0500
bcache: use wrappers for bcache read write in lvm
Using a wrapper makes it easier to disable bcache if needed.
---
lib/config/config.c | 4 +-
lib/device/dev-type.c | 4 +-
lib/format_text/archiver.c | 2 +-
lib/format_text/format-text.c | 19 ++++-----
lib/label/label.c | 82 +++++++++++++++++++++++++++++++++++++---
lib/label/label.h | 8 ++++
lib/metadata/metadata.c | 2 +-
tools/toollib.c | 2 +-
8 files changed, 99 insertions(+), 24 deletions(-)
diff --git a/lib/config/config.c b/lib/config/config.c
index 0711b8c..d07c173 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -534,11 +534,11 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
return 0;
}
- if (!bcache_read_bytes(scan_bcache, dev->bcache_fd, offset, size, buf))
+ if (!dev_read_bytes(dev, offset, size, buf))
goto out;
if (size2) {
- if (!bcache_read_bytes(scan_bcache, dev->bcache_fd, offset2, size2, buf + size))
+ if (!dev_read_bytes(dev, offset2, size2, buf + size))
goto out;
}
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index e69f7ca..9923943 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -677,7 +677,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
} else
log_verbose(_msg_wiping, type, name);
- if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, offset_value, len)) {
+ if (!dev_write_zeros(dev, offset_value, len)) {
log_error("Failed to wipe %s signature on %s.", type, name);
return 0;
}
@@ -774,7 +774,7 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam
}
log_print_unless_silent("Wiping %s on %s.", type, name);
- if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, offset_found, wipe_len)) {
+ if (!dev_write_zeros(dev, offset_found, wipe_len)) {
log_error("Failed to wipe %s on %s.", type, name);
return 0;
}
diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c
index 43ae4eb..c8aeb47 100644
--- a/lib/format_text/archiver.c
+++ b/lib/format_text/archiver.c
@@ -489,7 +489,7 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg,
log_verbose("Zeroing start of device %s", pv_name);
- if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, 0, 2048)) {
+ if (!dev_write_zeros(dev, 0, 2048)) {
log_error("%s not wiped: aborting", pv_name);
return 0;
}
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 4eef72e..4a9c303 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -227,7 +227,7 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
if (!(buf = dm_malloc(size + size2)))
goto_out;
- if (!bcache_read_bytes(scan_bcache, area->dev->bcache_fd, offset, size, buf)) {
+ if (!dev_read_bytes(area->dev, offset, size, buf)) {
log_error("Failed to read dev %s offset %llu size %llu",
dev_name(area->dev),
(unsigned long long)offset,
@@ -236,7 +236,7 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
}
if (size2) {
- if (!bcache_read_bytes(scan_bcache, area->dev->bcache_fd, offset2, size2, buf + size)) {
+ if (!dev_read_bytes(area->dev, offset2, size2, buf + size)) {
log_error("Failed to read dev %s offset %llu size %llu",
dev_name(area->dev),
(unsigned long long)offset2,
@@ -330,7 +330,7 @@ static int _raw_read_mda_header(struct mda_header *mdah, struct device_area *dev
log_debug_metadata("Reading mda header sector from %s at %llu",
dev_name(dev_area->dev), (unsigned long long)dev_area->start);
- if (!bcache_read_bytes(scan_bcache, dev_area->dev->bcache_fd, dev_area->start, MDA_HEADER_SIZE, mdah)) {
+ if (!dev_read_bytes(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah)) {
log_error("Failed to read metadata area header on %s at %llu",
dev_name(dev_area->dev), (unsigned long long)dev_area->start);
return 0;
@@ -400,7 +400,7 @@ static int _raw_write_mda_header(const struct format_type *fmt,
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)));
- if (!bcache_write_bytes(scan_bcache, dev->bcache_fd, start_byte, MDA_HEADER_SIZE, mdah)) {
+ if (!dev_write_bytes(dev, start_byte, MDA_HEADER_SIZE, mdah)) {
log_error("Failed to write mda header to %s fd %d", dev_name(dev), dev->bcache_fd);
return 0;
}
@@ -464,7 +464,7 @@ static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
*/
memset(vgnamebuf, 0, sizeof(vgnamebuf));
- bcache_read_bytes(scan_bcache, dev_area->dev->bcache_fd, dev_area->start + rlocn->offset, NAME_LEN, vgnamebuf);
+ dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, vgnamebuf);
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{'))
@@ -675,7 +675,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
(unsigned long long)(mdac->rlocn.size - new_wrap),
(unsigned long long)new_wrap);
- if (!bcache_write_bytes(scan_bcache, mdac->area.dev->bcache_fd, mdac->area.start + mdac->rlocn.offset,
+ if (!dev_write_bytes(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
(size_t) (mdac->rlocn.size - new_wrap),
fidtc->raw_metadata_buf)) {
log_error("Failed to write metadata to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
@@ -688,8 +688,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
(unsigned long long)(mdac->area.start + MDA_HEADER_SIZE),
(unsigned long long)new_wrap);
- if (!bcache_write_bytes(scan_bcache, mdac->area.dev->bcache_fd,
- mdac->area.start + MDA_HEADER_SIZE,
+ if (!dev_write_bytes(mdac->area.dev, mdac->area.start + MDA_HEADER_SIZE,
(size_t) new_wrap,
fidtc->raw_metadata_buf + mdac->rlocn.size - new_wrap)) {
log_error("Failed to write metadata wrap to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
@@ -1217,7 +1216,7 @@ int read_metadata_location_summary(const struct format_type *fmt,
return 0;
}
- bcache_read_bytes(scan_bcache, dev_area->dev->bcache_fd, dev_area->start + rlocn->offset, NAME_LEN, buf);
+ dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, buf);
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
len < (NAME_LEN - 1))
@@ -2308,7 +2307,7 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
zero_len = (mda_size > wipe_size) ? wipe_size : mda_size;
- if (!bcache_write_zeros(scan_bcache, pv->dev->bcache_fd, mda_start, zero_len)) {
+ if (!dev_write_zeros(pv->dev, mda_start, zero_len)) {
log_error("Failed to wipe new metadata area on %s at %llu len %llu",
pv_dev_name(pv),
(unsigned long long)mda_start,
diff --git a/lib/label/label.c b/lib/label/label.c
index 67d441b..45a3ecf 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -125,8 +125,7 @@ int label_remove(struct device *dev)
memset(readbuf, 0, sizeof(readbuf));
- if (!bcache_read_bytes(scan_bcache, dev->bcache_fd,
- sector << SECTOR_SHIFT, LABEL_SIZE, readbuf)) {
+ if (!dev_read_bytes(dev, sector << SECTOR_SHIFT, LABEL_SIZE, readbuf)) {
log_error("Failed to read label from %s sector %llu",
dev_name(dev), (unsigned long long)sector);
continue;
@@ -152,8 +151,7 @@ int label_remove(struct device *dev)
log_very_verbose("%s: Wiping label at sector %llu",
dev_name(dev), (unsigned long long)sector);
- if (!bcache_write_zeros(scan_bcache, dev->bcache_fd,
- sector << SECTOR_SHIFT, LABEL_SIZE)) {
+ if (!dev_write_zeros(dev, sector << SECTOR_SHIFT, LABEL_SIZE)) {
log_error("Failed to remove label from %s at sector %llu",
dev_name(dev), (unsigned long long)sector);
r = 0;
@@ -166,7 +164,6 @@ int label_remove(struct device *dev)
}
}
- out:
return r;
}
@@ -209,8 +206,7 @@ int label_write(struct device *dev, struct label *label)
return 0;
}
- if (!bcache_write_bytes(scan_bcache, dev->bcache_fd,
- label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
+ if (!dev_write_bytes(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
log_debug_devs("Failed to write label to %s", dev_name(dev));
r = 0;
}
@@ -856,3 +852,75 @@ int label_scan_open(struct device *dev)
return 1;
}
+bool dev_read_bytes(struct device *dev, off_t start, size_t len, void *data)
+{
+ int ret;
+
+ if (!scan_bcache) {
+ if (!dev_open_readonly(dev))
+ return false;
+
+ ret = dev_read(dev, start, len, 0, data);
+
+ if (!dev_close(dev))
+ stack;
+
+ return ret ? true : false;
+ }
+
+ if (dev->bcache_fd <= 0) {
+ log_error("dev_read_bytes %s with invalid bcache_fd", dev_name(dev));
+ return false;
+ }
+
+ return bcache_read_bytes(scan_bcache, dev->bcache_fd, start, len, data);
+}
+
+bool dev_write_bytes(struct device *dev, off_t start, size_t len, void *data)
+{
+ int ret;
+
+ if (!scan_bcache) {
+ if (!dev_open(dev))
+ return false;
+
+ ret = dev_write(dev, start, len, 0, data);
+
+ if (!dev_close(dev))
+ stack;
+
+ return ret ? true : false;
+ }
+
+ if (dev->bcache_fd <= 0) {
+ log_error("dev_write_bytes %s with invalid bcache_fd", dev_name(dev));
+ return false;
+ }
+
+ return bcache_write_bytes(scan_bcache, dev->bcache_fd, start, len, data);
+}
+
+bool dev_write_zeros(struct device *dev, off_t start, size_t len)
+{
+ int ret;
+
+ if (!scan_bcache) {
+ if (!dev_open(dev))
+ return false;
+
+ ret = dev_set(dev, start, len, 0, 0);
+
+ if (!dev_close(dev))
+ stack;
+
+ return ret ? true : false;
+ }
+
+ if (dev->bcache_fd <= 0) {
+ log_error("dev_write_bytes %s with invalid bcache_fd", dev_name(dev));
+ return false;
+ }
+
+ return bcache_write_zeros(scan_bcache, dev->bcache_fd, start, len);
+}
+
diff --git a/lib/label/label.h b/lib/label/label.h
index 92f3e7b..8ef687b 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -114,4 +114,12 @@ void label_scan_confirm(struct device *dev);
int label_scan_setup_bcache(void);
int label_scan_open(struct device *dev);
+/*
+ * Wrappers around bcache equivalents.
+ * (these make it easier to disable bcache and revert to direct rw if needed)
+ */
+bool dev_read_bytes(struct device *dev, off_t start, size_t len, void *data);
+bool dev_write_bytes(struct device *dev, off_t start, size_t len, void *data);
+bool dev_write_zeros(struct device *dev, off_t start, size_t len);
+
#endif
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 4cad2a1..b442451 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -1429,7 +1429,7 @@ static int _pvcreate_write(struct cmd_context *cmd, struct pv_to_write *pvw)
if (pvw->pp->zero) {
log_verbose("Zeroing start of device %s", pv_name);
- if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, 0, 2048)) {
+ if (!dev_write_zeros(dev, 0, 2048)) {
log_error("%s not wiped: aborting", pv_name);
return 0;
}
diff --git a/tools/toollib.c b/tools/toollib.c
index b0c0e8e..b029a0d 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -5830,7 +5830,7 @@ do_command:
if (pp->zero) {
log_verbose("Zeroing start of device %s.", pv_name);
- if (!bcache_write_zeros(scan_bcache, pv->dev->bcache_fd, 0, 2048)) {
+ if (!dev_write_zeros(pv->dev, 0, 2048)) {
log_error("%s not wiped: aborting.", pv_name);
dm_list_move(&pp->arg_fail, &pd->list);
continue;
6 years
master - [device/bcache] some more work on bcache
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=0f0eb04edb00cb5e95c...
Commit: 0f0eb04edb00cb5e95c47cb9ca2e70574e6e49ce
Parent: 46867a45d28ecb667d08df8d8cb497fffc10814d
Author: Joe Thornber <ejt(a)redhat.com>
AuthorDate: Thu Feb 1 14:52:43 2018 +0000
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:12:50 2018 -0500
[device/bcache] some more work on bcache
---
lib/device/bcache.c | 99 ++++++++++++++++++++++-----------
lib/device/bcache.h | 2 +-
test/unit/Makefile.in | 2 +-
test/unit/bcache_t.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 216 insertions(+), 34 deletions(-)
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 3b8cf78..5a7b2f9 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -167,12 +167,19 @@ static struct io_engine *_engine_create(unsigned max_io)
static void _engine_destroy(struct io_engine *e)
{
+ int r;
+
_cb_set_destroy(e->cbs);
- io_destroy(e->aio_context);
+
+ // io_destroy is really slow
+ r = io_destroy(e->aio_context);
+ if (r)
+ log_sys_warn("io_destroy");
+
dm_free(e);
}
-static bool _engine_issue(struct io_engine *e, int fd, enum dir d,
+static bool _engine_issue(struct io_engine *e, enum dir d, int fd,
sector_t sb, sector_t se, void *data, void *context)
{
int r;
@@ -290,7 +297,6 @@ enum block_flags {
};
struct bcache {
- int fd;
sector_t block_sectors;
uint64_t nr_data_blocks;
uint64_t nr_cache_blocks;
@@ -488,6 +494,30 @@ static void _relink(struct block *b)
*
*--------------------------------------------------------------*/
+static void _complete_io(void *context, int err)
+{
+ struct block *b = context;
+ struct bcache *cache = b->cache;
+
+ b->error = err;
+ _clear_flags(b, BF_IO_PENDING);
+ cache->nr_io_pending--;
+
+ /*
+ * b is on the io_pending list, so we don't want to use unlink_block.
+ * Which would incorrectly adjust nr_dirty.
+ */
+ dm_list_del(&b->list);
+
+ if (b->error)
+ dm_list_add(&cache->errored, &b->list);
+
+ else {
+ _clear_flags(b, BF_DIRTY);
+ _link_block(b);
+ }
+}
+
/*
* |b->list| should be valid (either pointing to itself, on one of the other
* lists.
@@ -502,7 +532,13 @@ static bool _issue_low_level(struct block *b, enum dir d)
return false;
_set_flags(b, BF_IO_PENDING);
- return _engine_issue(cache->engine, cache->fd, d, sb, se, b->data, b);
+ if (!_engine_issue(cache->engine, d, b->fd, sb, se, b->data, b)) {
+ _complete_io(b, -EIO);
+ return false;
+ }
+
+ return true;
+
}
static inline bool _issue_read(struct block *b)
@@ -515,30 +551,6 @@ static inline bool _issue_write(struct block *b)
return _issue_low_level(b, DIR_WRITE);
}
-static void _complete_io(void *context, int err)
-{
- struct block *b = context;
- struct bcache *cache = b->cache;
-
- b->error = err;
- _clear_flags(b, BF_IO_PENDING);
- cache->nr_io_pending--;
-
- /*
- * b is on the io_pending list, so we don't want to use unlink_block.
- * Which would incorrectly adjust nr_dirty.
- */
- dm_list_del(&b->list);
-
- if (b->error)
- dm_list_add(&cache->errored, &b->list);
-
- else {
- _clear_flags(b, BF_DIRTY);
- _link_block(b);
- }
-}
-
static bool _wait_io(struct bcache *cache)
{
return _engine_wait(cache->engine, _complete_io);
@@ -598,7 +610,7 @@ static struct block *_find_unused_clean_block(struct bcache *cache)
return NULL;
}
-static struct block *_new_block(struct bcache *cache, block_address index)
+static struct block *_new_block(struct bcache *cache, int fd, block_address index)
{
struct block *b;
@@ -616,6 +628,7 @@ static struct block *_new_block(struct bcache *cache, block_address index)
dm_list_init(&b->list);
dm_list_init(&b->hash);
b->flags = 0;
+ b->fd = fd;
b->index = index;
b->ref_count = 0;
b->error = 0;
@@ -685,7 +698,7 @@ static struct block *_lookup_or_read_block(struct bcache *cache,
} else {
_miss(cache, flags);
- b = _new_block(cache, index);
+ b = _new_block(cache, fd, index);
if (b) {
if (flags & GF_ZERO)
_zero_block(b);
@@ -728,6 +741,21 @@ struct bcache *bcache_create(sector_t block_sectors, unsigned nr_cache_blocks)
{
struct bcache *cache;
+ if (!nr_cache_blocks) {
+ log_warn("bcache must have at least one cache block");
+ return NULL;
+ }
+
+ if (!block_sectors) {
+ log_warn("bcache must have a non zero block size");
+ return NULL;
+ }
+
+ if (block_sectors & ((PAGE_SIZE >> SECTOR_SHIFT) - 1)) {
+ log_warn("bcache block size must be a multiple of page size");
+ return NULL;
+ }
+
cache = dm_malloc(sizeof(*cache));
if (!cache)
return NULL;
@@ -787,6 +815,11 @@ void bcache_destroy(struct bcache *cache)
dm_free(cache);
}
+unsigned bcache_nr_cache_blocks(struct bcache *cache)
+{
+ return cache->nr_cache_blocks;
+}
+
void bcache_prefetch(struct bcache *cache, int fd, block_address index)
{
struct block *b = _hash_lookup(cache, fd, index);
@@ -794,7 +827,7 @@ void bcache_prefetch(struct bcache *cache, int fd, block_address index)
if (!b) {
cache->prefetches++;
- b = _new_block(cache, index);
+ b = _new_block(cache, fd, index);
if (b)
_issue_read(b);
}
@@ -803,7 +836,9 @@ void bcache_prefetch(struct bcache *cache, int fd, block_address index)
bool bcache_get(struct bcache *cache, int fd, block_address index,
unsigned flags, struct block **result)
{
- struct block *b = _lookup_or_read_block(cache, fd, index, flags);
+ struct block *b;
+
+ b = _lookup_or_read_block(cache, fd, index, flags);
if (b) {
if (!b->ref_count)
cache->nr_locked++;
diff --git a/lib/device/bcache.h b/lib/device/bcache.h
index 0747b5a..2730347 100644
--- a/lib/device/bcache.h
+++ b/lib/device/bcache.h
@@ -61,7 +61,7 @@ enum bcache_get_flags {
typedef uint64_t block_address;
-unsigned bcache_get_max_prefetches(struct bcache *cache);
+unsigned bcache_nr_cache_blocks(struct bcache *cache);
/*
* Use the prefetch method to take advantage of asynchronous IO. For example,
diff --git a/test/unit/Makefile.in b/test/unit/Makefile.in
index 8127ec0..5cf92ba 100644
--- a/test/unit/Makefile.in
+++ b/test/unit/Makefile.in
@@ -47,7 +47,7 @@ $(TARGETS): $(OBJECTS) $(top_builddir)/libdm/libdevmapper.$(LIB_SUFFIX)
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) -L$(top_builddir)/libdm \
-o $@ $(OBJECTS) $(LDLIBS)
-unit: $(TARGETS)
+unit: $(TARGETS) $(top_builddir)/lib/liblvm-internal.a
@echo Running unit tests
LD_LIBRARY_PATH=$(top_builddir)/libdm ./$(TARGETS)
endif
diff --git a/test/unit/bcache_t.c b/test/unit/bcache_t.c
index da274a9..ef92721 100644
--- a/test/unit/bcache_t.c
+++ b/test/unit/bcache_t.c
@@ -12,9 +12,21 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
#include "units.h"
#include "bcache.h"
+#define MEG 2048
+#define SECTOR_SHIFT 9
+
+static const char *_test_path = "test.bin";
+
int bcache_init(void)
{
return 0;
@@ -25,6 +37,42 @@ int bcache_fini(void)
return 0;
}
+static int open_file(const char *path)
+{
+ return open(path, O_EXCL | O_RDWR | O_DIRECT, 0666);
+}
+
+static int _prep_file(const char *path)
+{
+ int fd, r;
+
+ fd = open(path, O_CREAT | O_TRUNC | O_EXCL | O_RDWR | O_DIRECT, 0666);
+ if (fd < 0)
+ return -1;
+
+ r = fallocate(fd, FALLOC_FL_ZERO_RANGE, 0, (16 * MEG) << SECTOR_SHIFT);
+ if (r) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+static int test_init(void)
+{
+ unlink(_test_path);
+ return _prep_file(_test_path);
+}
+
+static int test_exit(void)
+{
+ unlink(_test_path);
+ return 0;
+}
+
static void test_create(void)
{
struct bcache *cache = bcache_create(8, 16);
@@ -32,7 +80,106 @@ static void test_create(void)
bcache_destroy(cache);
}
+static void test_nr_cache_blocks_must_be_positive(void)
+{
+ struct bcache *cache = bcache_create(8, 0);
+ CU_ASSERT_PTR_NULL(cache);
+}
+
+static void test_block_size_must_be_positive(void)
+{
+ struct bcache *cache = bcache_create(0, 16);
+ CU_ASSERT_PTR_NULL(cache);
+}
+
+static void test_block_size_must_be_multiple_of_page_size(void)
+{
+ unsigned i;
+ struct bcache *cache;
+
+ {
+ static unsigned _bad_examples[] = {3, 9, 13, 1025};
+
+ for (i = 0; i < DM_ARRAY_SIZE(_bad_examples); i++) {
+ cache = bcache_create(_bad_examples[i], 16);
+ CU_ASSERT_PTR_NULL(cache);
+ }
+ }
+
+ {
+ // Only testing a few sizes because io_destroy is seriously
+ // slow.
+ for (i = 1; i < 25; i++) {
+ cache = bcache_create(8 * i, 16);
+ CU_ASSERT_PTR_NOT_NULL(cache);
+ bcache_destroy(cache);
+ }
+ }
+}
+
+static void test_reads_work(void)
+{
+ int fd;
+
+ // FIXME: add fixtures.
+ test_init();
+ fd = open_file("./test.bin");
+ CU_ASSERT(fd >= 0);
+
+ {
+ int i;
+ struct block *b;
+ struct bcache *cache = bcache_create(8, 16);
+
+ CU_ASSERT(bcache_get(cache, fd, 0, 0, &b));
+ for (i = 0; i < 8 << SECTOR_SHIFT; i++)
+ CU_ASSERT(((unsigned char *) b->data)[i] == 0);
+ bcache_put(b);
+
+ bcache_destroy(cache);
+ }
+
+ close(fd);
+
+ test_exit();
+}
+
+static void test_prefetch_works(void)
+{
+ int fd;
+
+ // FIXME: add fixtures.
+ test_init();
+ fd = open_file("./test.bin");
+ CU_ASSERT(fd >= 0);
+
+ {
+ int i;
+ struct block *b;
+ struct bcache *cache = bcache_create(8, 16);
+
+ for (i = 0; i < 16; i++)
+ bcache_prefetch(cache, fd, i);
+
+ for (i = 0; i < 16; i++) {
+ CU_ASSERT(bcache_get(cache, fd, i, 0, &b));
+ bcache_put(b);
+ }
+
+ bcache_destroy(cache);
+ }
+
+ close(fd);
+
+ test_exit();
+}
+
CU_TestInfo bcache_list[] = {
{ (char*)"create", test_create },
+ { (char*)"nr cache block must be positive", test_nr_cache_blocks_must_be_positive },
+ { (char*)"block size must be positive", test_block_size_must_be_positive },
+ { (char*)"block size must be multiple of page size", test_block_size_must_be_multiple_of_page_size },
+ { (char*)"reads work", test_reads_work },
+ { (char*)"prefetch works", test_prefetch_works },
CU_TEST_INFO_NULL
};
6 years
master - bcache: do all writes through bcache
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=80654920468841251a7...
Commit: 80654920468841251a7f940e410ca61de8383b41
Parent: 8b26a007b1b545333b40675b1c425b1ef5e0b653
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Feb 19 15:40:44 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:47 2018 -0500
bcache: do all writes through bcache
---
lib/device/bcache.c | 86 ++++++++++++++++++++++++++++++-
lib/device/bcache.h | 4 +-
lib/device/dev-type.c | 6 ++-
lib/format_text/archiver.c | 10 +---
lib/format_text/format-text.c | 94 +++++++++++++---------------------
lib/label/label.c | 112 +++++++++++++++++++----------------------
lib/label/label.h | 1 +
lib/metadata/metadata.c | 19 +++----
tools/toollib.c | 17 ++----
9 files changed, 193 insertions(+), 156 deletions(-)
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 499c6af..272de60 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -897,7 +897,7 @@ bool bcache_get(struct bcache *cache, int fd, block_address index,
return false;
}
-void bcache_put(struct block *b)
+static void _put_ref(struct block *b)
{
if (!b->ref_count) {
log_warn("ref count on bcache block already zero");
@@ -907,6 +907,11 @@ void bcache_put(struct block *b)
b->ref_count--;
if (!b->ref_count)
b->cache->nr_locked--;
+}
+
+void bcache_put(struct block *b)
+{
+ _put_ref(b);
if (_test_flags(b, BF_DIRTY))
_preemptive_writeback(b->cache);
@@ -925,7 +930,7 @@ bool bcache_flush(struct bcache *cache)
// The superblock may well be still locked.
continue;
}
-
+
_issue_write(b);
}
@@ -1058,5 +1063,82 @@ bool bcache_read_bytes(struct bcache *cache, int fd, off_t start, size_t len, vo
return errors ? false : true;
}
+bool bcache_write_bytes(struct bcache *cache, int fd, off_t start, size_t len, void *data)
+{
+ struct block *b;
+ block_address bb, be, i;
+ unsigned char *udata = data;
+ off_t block_size = cache->block_sectors << 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, 0, &b)) {
+ errors++;
+ break;
+ }
+
+ if (i == bb) {
+ off_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;
+ udata += blen;
+ } else {
+ size_t blen = _min(block_size, len);
+ memcpy(b->data, udata, blen);
+ len -= blen;
+ udata += blen;
+ }
+
+ _set_flags(b, BF_DIRTY);
+ _unlink_block(b);
+ _link_block(b);
+ _put_ref(b);
+ }
+
+ if (!bcache_flush(cache))
+ errors++;
+
+ return errors ? false : true;
+}
+
+#define ZERO_BUF_LEN 4096
+
+bool bcache_write_zeros(struct bcache *cache, int fd, off_t start, size_t len)
+{
+ char zerobuf[ZERO_BUF_LEN];
+ size_t plen;
+ size_t poff;
+
+ memset(zerobuf, 0, sizeof(zerobuf));
+
+ if (len <= ZERO_BUF_LEN)
+ return bcache_write_bytes(cache, fd, start, len, &zerobuf);
+
+ poff = 0;
+ plen = ZERO_BUF_LEN;
+
+ while (1) {
+ if (!bcache_write_bytes(cache, fd, start + poff, plen, &zerobuf))
+ return false;
+
+ poff += plen;
+ len -= plen;
+
+ if (!len)
+ break;
+
+ if (len < ZERO_BUF_LEN)
+ plen = len;
+ }
+
+ return true;
+}
+
+
//----------------------------------------------------------------
diff --git a/lib/device/bcache.h b/lib/device/bcache.h
index e5d98e8..d5f6d0a 100644
--- a/lib/device/bcache.h
+++ b/lib/device/bcache.h
@@ -148,9 +148,11 @@ void bcache_invalidate_fd(struct bcache *cache, int fd);
void bcache_prefetch_bytes(struct bcache *cache, int fd, off_t start, size_t len);
/*
- * Reads the bytes.
+ * Reads and writes the bytes. Returns false if errors occur.
*/
bool bcache_read_bytes(struct bcache *cache, int fd, off_t start, size_t len, void *data);
+bool bcache_write_bytes(struct bcache *cache, int fd, off_t start, size_t len, void *data);
+bool bcache_write_zeros(struct bcache *cache, int fd, off_t start, size_t len);
/*----------------------------------------------------------------*/
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index 9608146..e69f7ca 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -17,6 +17,8 @@
#include "xlate.h"
#include "config.h"
#include "metadata.h"
+#include "bcache.h"
+#include "label.h"
#include <libgen.h>
#include <ctype.h>
@@ -675,7 +677,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
} else
log_verbose(_msg_wiping, type, name);
- if (!dev_set(dev, offset_value, len, DEV_IO_SIGNATURES, 0)) {
+ if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, offset_value, len)) {
log_error("Failed to wipe %s signature on %s.", type, name);
return 0;
}
@@ -772,7 +774,7 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam
}
log_print_unless_silent("Wiping %s on %s.", type, name);
- if (!dev_set(dev, offset_found, wipe_len, DEV_IO_SIGNATURES, 0)) {
+ if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, offset_found, wipe_len)) {
log_error("Failed to wipe %s on %s.", type, name);
return 0;
}
diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c
index 81b5da9..43ae4eb 100644
--- a/lib/format_text/archiver.c
+++ b/lib/format_text/archiver.c
@@ -488,19 +488,11 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg,
}
log_verbose("Zeroing start of device %s", pv_name);
- if (!dev_open_quiet(dev)) {
- log_error("%s not opened: device not zeroed", pv_name);
- return 0;
- }
- if (!dev_set(dev, UINT64_C(0), (size_t) 2048, DEV_IO_LABEL, 0)) {
+ if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, 0, 2048)) {
log_error("%s not wiped: aborting", pv_name);
- if (!dev_close(dev))
- stack;
return 0;
}
- if (!dev_close(dev))
- stack;
}
}
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index ef59f07..4eef72e 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -330,8 +330,6 @@ static int _raw_read_mda_header(struct mda_header *mdah, struct device_area *dev
log_debug_metadata("Reading mda header sector from %s at %llu",
dev_name(dev_area->dev), (unsigned long long)dev_area->start);
- label_scan_confirm(dev_area->dev); /* FIXME: remove this, ensures dev is in bcache */
-
if (!bcache_read_bytes(scan_bcache, dev_area->dev->bcache_fd, dev_area->start, MDA_HEADER_SIZE, mdah)) {
log_error("Failed to read metadata area header on %s at %llu",
dev_name(dev_area->dev), (unsigned long long)dev_area->start);
@@ -397,24 +395,16 @@ static int _raw_write_mda_header(const struct format_type *fmt,
mdah->version = FMTT_VERSION;
mdah->start = start_byte;
- label_scan_invalidate(dev);
-
- if (!dev_open(dev))
- return_0;
-
_xlate_mdah(mdah);
mdah->checksum_xl = xlate32(calc_crc(INITIAL_CRC, (uint8_t *)mdah->magic,
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)));
- if (!dev_write(dev, start_byte, MDA_HEADER_SIZE, MDA_HEADER_REASON(primary_mda), mdah)) {
- dev_close(dev);
- return_0;
+ if (!bcache_write_bytes(scan_bcache, dev->bcache_fd, start_byte, MDA_HEADER_SIZE, mdah)) {
+ log_error("Failed to write mda header to %s fd %d", dev_name(dev), dev->bcache_fd);
+ return 0;
}
- if (dev_close(dev))
- stack;
-
return 1;
}
@@ -474,8 +464,6 @@ static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
*/
memset(vgnamebuf, 0, sizeof(vgnamebuf));
- label_scan_confirm(dev_area->dev); /* FIXME: remove this, ensures dev is in bcache */
-
bcache_read_bytes(scan_bcache, dev_area->dev->bcache_fd, dev_area->start + rlocn->offset, NAME_LEN, vgnamebuf);
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
@@ -681,30 +669,32 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
- log_debug_metadata("Writing %s metadata to %s at " FMTu64 " len " FMTu64 " of " FMTu64,
- vg->name, dev_name(mdac->area.dev), mdac->area.start +
- mdac->rlocn.offset, mdac->rlocn.size - new_wrap, mdac->rlocn.size);
-
- label_scan_invalidate(mdac->area.dev);
-
- if (!dev_open(mdac->area.dev))
- return_0;
+ log_debug_metadata("Writing metadata for VG %s to %s at %llu len %llu (wrap %llu)",
+ vg->name, dev_name(mdac->area.dev),
+ (unsigned long long)(mdac->area.start + mdac->rlocn.offset),
+ (unsigned long long)(mdac->rlocn.size - new_wrap),
+ (unsigned long long)new_wrap);
- /* Write text out, circularly */
- if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
- (size_t) (mdac->rlocn.size - new_wrap), MDA_CONTENT_REASON(mda_is_primary(mda)),
- fidtc->raw_metadata_buf))
- goto_out;
+ if (!bcache_write_bytes(scan_bcache, mdac->area.dev->bcache_fd, mdac->area.start + mdac->rlocn.offset,
+ (size_t) (mdac->rlocn.size - new_wrap),
+ fidtc->raw_metadata_buf)) {
+ log_error("Failed to write metadata to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
+ goto out;
+ }
if (new_wrap) {
- log_debug_metadata("Writing wrapped metadata to %s at " FMTu64 " len " FMTu64 " of " FMTu64,
- dev_name(mdac->area.dev), mdac->area.start +
- MDA_HEADER_SIZE, new_wrap, mdac->rlocn.size);
-
- if (!dev_write(mdac->area.dev, mdac->area.start + MDA_HEADER_SIZE,
- (size_t) new_wrap, MDA_CONTENT_REASON(mda_is_primary(mda)),
- fidtc->raw_metadata_buf + mdac->rlocn.size - new_wrap))
- goto_out;
+ log_debug_metadata("Writing metadata for VG %s to %s at %llu len %llu (wrapped)",
+ vg->name, dev_name(mdac->area.dev),
+ (unsigned long long)(mdac->area.start + MDA_HEADER_SIZE),
+ (unsigned long long)new_wrap);
+
+ if (!bcache_write_bytes(scan_bcache, mdac->area.dev->bcache_fd,
+ mdac->area.start + MDA_HEADER_SIZE,
+ (size_t) new_wrap,
+ fidtc->raw_metadata_buf + mdac->rlocn.size - new_wrap)) {
+ log_error("Failed to write metadata wrap to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
+ goto out;
+ }
}
mdac->rlocn.checksum = calc_crc(INITIAL_CRC, (uint8_t *)fidtc->raw_metadata_buf,
@@ -720,9 +710,6 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
out:
if (!r) {
- if (!dev_close(mdac->area.dev))
- stack;
-
dm_free(fidtc->raw_metadata_buf);
fidtc->raw_metadata_buf = NULL;
}
@@ -819,9 +806,6 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
out:
if (!precommit) {
- if (!dev_close(mdac->area.dev))
- stack;
-
dm_free(fidtc->raw_metadata_buf);
fidtc->raw_metadata_buf = NULL;
}
@@ -904,9 +888,6 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
rlocn->checksum = 0;
rlocn_set_ignored(mdah->raw_locns, mda_is_ignored(mda));
- if (!dev_open(mdac->area.dev))
- return_0;
-
if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mda_is_primary(mda), mdac->area.start,
mdah)) {
dm_pool_free(fid->fmt->cmd->mem, mdah);
@@ -917,9 +898,6 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
r = 1;
out:
- if (!dev_close(mdac->area.dev))
- stack;
-
return r;
}
@@ -1239,8 +1217,6 @@ int read_metadata_location_summary(const struct format_type *fmt,
return 0;
}
- label_scan_confirm(dev_area->dev); /* FIXME: remove this, ensures dev is in bcache */
-
bcache_read_bytes(scan_bcache, dev_area->dev->bcache_fd, dev_area->start + rlocn->offset, NAME_LEN, buf);
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
@@ -1397,8 +1373,6 @@ static int _write_single_mda(struct metadata_area *mda, void *baton)
if (!_raw_write_mda_header(p->fmt, mdac->area.dev, mda_is_primary(mda),
mdac->area.start, mdah)) {
- if (!dev_close(p->pv->dev))
- stack;
return_0;
}
return 1;
@@ -2123,6 +2097,7 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
uint64_t mda_start;
uint64_t adjustment, limit, tmp_mda_size;
uint64_t wipe_size = 8 << SECTOR_SHIFT;
+ uint64_t zero_len;
size_t page_size = lvm_getpagesize();
struct metadata_area *mda;
struct mda_context *mdac;
@@ -2330,13 +2305,14 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
}
/* Wipe metadata area with zeroes. */
- if (!dev_set(pv->dev, mda_start,
- (size_t) ((mda_size > wipe_size) ? wipe_size : mda_size),
- MDA_HEADER_REASON(!mda_index), 0)) {
- log_error("Failed to wipe new metadata area "
- "at the %s of the %s",
- mda_index ? "end" : "start",
- pv_dev_name(pv));
+
+ zero_len = (mda_size > wipe_size) ? wipe_size : mda_size;
+
+ if (!bcache_write_zeros(scan_bcache, pv->dev->bcache_fd, mda_start, zero_len)) {
+ log_error("Failed to wipe new metadata area on %s at %llu len %llu",
+ pv_dev_name(pv),
+ (unsigned long long)mda_start,
+ (unsigned long long)zero_len);
return 0;
}
diff --git a/lib/label/label.c b/lib/label/label.c
index 278f26a..67d441b 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -104,8 +104,7 @@ struct labeller *label_get_handler(const char *name)
/* FIXME Also wipe associated metadata area headers? */
int label_remove(struct device *dev)
{
- char buf[LABEL_SIZE] __attribute__((aligned(8)));
- char readbuf[LABEL_SCAN_SIZE] __attribute__((aligned(8)));
+ char readbuf[LABEL_SIZE] __attribute__((aligned(8)));
int r = 1;
uint64_t sector;
int wipe;
@@ -113,31 +112,27 @@ int label_remove(struct device *dev)
struct label_header *lh;
struct lvmcache_info *info;
- memset(buf, 0, LABEL_SIZE);
-
log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev));
- label_scan_invalidate(dev);
-
- if (!dev_open(dev))
- return_0;
-
- /*
- * We flush the device just in case someone is stupid
- * enough to be trying to import an open pv into lvm.
- */
- dev_flush(dev);
-
- if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, DEV_IO_LABEL, readbuf)) {
- log_debug_devs("%s: Failed to read label area", dev_name(dev));
- goto out;
+ if (!label_scan_open(dev)) {
+ log_error("Failed to open device %s", dev_name(dev));
+ return 0;
}
/* Scan first few sectors for anything looking like a label */
for (sector = 0; sector < LABEL_SCAN_SECTORS;
sector += LABEL_SIZE >> SECTOR_SHIFT) {
- lh = (struct label_header *) (readbuf +
- (sector << SECTOR_SHIFT));
+
+ memset(readbuf, 0, sizeof(readbuf));
+
+ if (!bcache_read_bytes(scan_bcache, dev->bcache_fd,
+ sector << SECTOR_SHIFT, LABEL_SIZE, readbuf)) {
+ log_error("Failed to read label from %s sector %llu",
+ dev_name(dev), (unsigned long long)sector);
+ continue;
+ }
+
+ lh = (struct label_header *)readbuf;
wipe = 0;
@@ -146,8 +141,7 @@ int label_remove(struct device *dev)
wipe = 1;
} else {
dm_list_iterate_items(li, &_labellers) {
- if (li->l->ops->can_handle(li->l, (char *) lh,
- sector)) {
+ if (li->l->ops->can_handle(li->l, (char *)lh, sector)) {
wipe = 1;
break;
}
@@ -155,27 +149,24 @@ int label_remove(struct device *dev)
}
if (wipe) {
- log_very_verbose("%s: Wiping label at sector %" PRIu64,
- dev_name(dev), sector);
- if (dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE, DEV_IO_LABEL,
- buf)) {
+ log_very_verbose("%s: Wiping label at sector %llu",
+ dev_name(dev), (unsigned long long)sector);
+
+ if (!bcache_write_zeros(scan_bcache, dev->bcache_fd,
+ sector << SECTOR_SHIFT, LABEL_SIZE)) {
+ log_error("Failed to remove label from %s at sector %llu",
+ dev_name(dev), (unsigned long long)sector);
+ r = 0;
+ } else {
/* Also remove the PV record from cache. */
info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
if (info)
lvmcache_del(info);
- } else {
- log_error("Failed to remove label from %s at "
- "sector %" PRIu64, dev_name(dev),
- sector);
- r = 0;
}
}
}
out:
- if (!dev_close(dev))
- stack;
-
return r;
}
@@ -197,8 +188,6 @@ int label_write(struct device *dev, struct label *label)
return 0;
}
- label_scan_invalidate(dev);
-
memset(buf, 0, LABEL_SIZE);
strncpy((char *)lh->id, LABEL_ID, sizeof(lh->id));
@@ -211,20 +200,21 @@ int label_write(struct device *dev, struct label *label)
lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
((uint8_t *) &lh->offset_xl - (uint8_t *) lh)));
- if (!dev_open(dev))
- return_0;
-
log_very_verbose("%s: Writing label to sector %" PRIu64 " with stored offset %"
PRIu32 ".", dev_name(dev), label->sector,
xlate32(lh->offset_xl));
- if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, DEV_IO_LABEL, buf)) {
+
+ if (!label_scan_open(dev)) {
+ log_error("Failed to open device %s", dev_name(dev));
+ return 0;
+ }
+
+ if (!bcache_write_bytes(scan_bcache, dev->bcache_fd,
+ label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
log_debug_devs("Failed to write label to %s", dev_name(dev));
r = 0;
}
- if (!dev_close(dev))
- stack;
-
return r;
}
@@ -763,8 +753,10 @@ void label_scan_destroy(struct cmd_context *cmd)
return;
}
- while ((dev = dev_iter_get(iter)))
- label_scan_invalidate(dev);
+ while ((dev = dev_iter_get(iter))) {
+ if (_in_bcache(dev))
+ _scan_dev_close(dev);
+ }
dev_iter_destroy(iter);
bcache_destroy(scan_bcache);
@@ -834,22 +826,6 @@ int label_read_sector(struct device *dev, struct label **labelp, uint64_t scan_s
}
/*
- * FIXME: remove this. It should not be needed once writes are going through
- * bcache. As it is now, the write path involves multiple writes to a device,
- * and later writes want to read previous writes from disk. They do these
- * reads using the standard read paths which require the devs to be in bcache,
- * but the bcache reads do not find the dev because the writes have gone around
- * bcache. To work around this for now, check if each dev is in bcache before
- * reading it, and if not add it first.
- */
-
-void label_scan_confirm(struct device *dev)
-{
- if (!_in_bcache(dev))
- label_read(dev, NULL, 0);
-}
-
-/*
* This is only needed when commands are using lvmetad, in which case they
* don't do an initial label_scan, but may later need to rescan certain devs
* from disk and call this function. FIXME: is there some better number to
@@ -866,3 +842,17 @@ int label_scan_setup_bcache(void)
return 1;
}
+/*
+ * This is needed to write to a new non-lvm device.
+ * Scanning that dev would not keep it open or in
+ * bcache, but to use bcache_write we need the dev
+ * to be open so we can use dev->bcache_fd to write.
+ */
+
+int label_scan_open(struct device *dev)
+{
+ if (!_in_bcache(dev))
+ return _scan_dev_open(dev);
+ return 1;
+}
+
diff --git a/lib/label/label.h b/lib/label/label.h
index bf6e926..92f3e7b 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -112,5 +112,6 @@ int label_read(struct device *dev, struct label **labelp, uint64_t unused_sector
int label_read_sector(struct device *dev, struct label **labelp, uint64_t scan_sector);
void label_scan_confirm(struct device *dev);
int label_scan_setup_bcache(void);
+int label_scan_open(struct device *dev);
#endif
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index b588a04..4cad2a1 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -692,6 +692,7 @@ int check_pv_dev_sizes(struct volume_group *vg)
* . lvmcache_get_vgids()
* . lvmcache_get_vgnames()
* . the vg->pvs_to_write list and pv_to_write struct
+ * . _pvcreate_write()
*/
int vg_extend_each_pv(struct volume_group *vg, struct pvcreate_params *pp)
@@ -1414,28 +1415,24 @@ static int _pvcreate_write(struct cmd_context *cmd, struct pv_to_write *pvw)
struct device *dev = pv->dev;
const char *pv_name = dev_name(dev);
+ if (!label_scan_open(dev)) {
+ log_error("%s not opened: device not written", pv_name);
+ return 0;
+ }
+
if (pvw->new_pv) {
/* Wipe existing label first */
- if (!label_remove(pv_dev(pv))) {
+ if (!label_remove(dev)) {
log_error("Failed to wipe existing label on %s", pv_name);
return 0;
}
if (pvw->pp->zero) {
log_verbose("Zeroing start of device %s", pv_name);
- if (!dev_open_quiet(dev)) {
- log_error("%s not opened: device not zeroed", pv_name);
- return 0;
- }
-
- if (!dev_set(dev, UINT64_C(0), (size_t) 2048, DEV_IO_LABEL, 0)) {
+ if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, 0, 2048)) {
log_error("%s not wiped: aborting", pv_name);
- if (!dev_close(dev))
- stack;
return 0;
}
- if (!dev_close(dev))
- stack;
}
}
diff --git a/tools/toollib.c b/tools/toollib.c
index 623bfbb..b0c0e8e 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -5728,6 +5728,8 @@ do_command:
* Wipe signatures on devices being created.
*/
dm_list_iterate_items_safe(pd, pd2, &pp->arg_create) {
+ label_scan_open(pd->dev);
+
log_verbose("Wiping signatures on new PV %s.", pd->name);
if (!wipe_known_signatures(cmd, pd->dev, pd->name, TYPE_LVM1_MEMBER | TYPE_LVM2_MEMBER,
@@ -5805,6 +5807,8 @@ do_command:
pv_name = pd->name;
+ label_scan_open(pd->dev);
+
log_debug("Creating a new PV on %s.", pv_name);
if (!(pv = pv_create(cmd, pd->dev, &pp->pva))) {
@@ -5816,6 +5820,7 @@ do_command:
log_verbose("Set up physical volume for \"%s\" with %" PRIu64
" available sectors.", pv_name, pv_size(pv));
+
if (!label_remove(pv->dev)) {
log_error("Failed to wipe existing label on %s.", pv_name);
dm_list_move(&pp->arg_fail, &pd->list);
@@ -5825,21 +5830,11 @@ do_command:
if (pp->zero) {
log_verbose("Zeroing start of device %s.", pv_name);
- if (!dev_open_quiet(pv->dev)) {
- log_error("%s not opened: device not zeroed.", pv_name);
- dm_list_move(&pp->arg_fail, &pd->list);
- continue;
- }
-
- if (!dev_set(pv->dev, UINT64_C(0), (size_t) 2048, DEV_IO_LABEL, 0)) {
+ if (!bcache_write_zeros(scan_bcache, pv->dev->bcache_fd, 0, 2048)) {
log_error("%s not wiped: aborting.", pv_name);
- if (!dev_close(pv->dev))
- stack;
dm_list_move(&pp->arg_fail, &pd->list);
continue;
}
- if (!dev_close(pv->dev))
- stack;
}
log_verbose("Writing physical volume data to disk \"%s\".", pv_name);
6 years
master - [device/bcache] stub a unit test
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=46867a45d28ecb667d0...
Commit: 46867a45d28ecb667d08df8d8cb497fffc10814d
Parent: cb2c4542a6028ef09d30bfdcdaef4e7ddb740ca7
Author: Joe Thornber <ejt(a)redhat.com>
AuthorDate: Thu Feb 1 09:54:56 2018 +0000
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:12:50 2018 -0500
[device/bcache] stub a unit test
---
include/.symlinks.in | 1 +
lib/device/bcache.h | 1 +
test/unit/Makefile.in | 3 ++-
test/unit/bcache_t.c | 38 ++++++++++++++++++++++++++++++++++++++
test/unit/run.c | 1 +
test/unit/units.h | 1 +
6 files changed, 44 insertions(+), 1 deletions(-)
diff --git a/include/.symlinks.in b/include/.symlinks.in
index a1b5c1e..3d50750 100644
--- a/include/.symlinks.in
+++ b/include/.symlinks.in
@@ -14,6 +14,7 @@
@top_srcdir(a)/lib/config/defaults.h
@top_srcdir(a)/lib/datastruct/btree.h
@top_srcdir(a)/lib/datastruct/str_list.h
+@top_srcdir(a)/lib/device/bcache.h
@top_srcdir(a)/lib/device/dev-cache.h
@top_srcdir(a)/lib/device/dev-ext-udev-constants.h
@top_srcdir(a)/lib/device/dev-type.h
diff --git a/lib/device/bcache.h b/lib/device/bcache.h
index 3227744..0747b5a 100644
--- a/lib/device/bcache.h
+++ b/lib/device/bcache.h
@@ -16,6 +16,7 @@
#define BCACHE_H
#include <stdint.h>
+#include <stdbool.h>
#include "libdevmapper.h"
diff --git a/test/unit/Makefile.in b/test/unit/Makefile.in
index 3de30f2..8127ec0 100644
--- a/test/unit/Makefile.in
+++ b/test/unit/Makefile.in
@@ -16,6 +16,7 @@ top_builddir = @top_builddir@
VPATH = $(srcdir)
UNITS = \
+ bcache_t.c \
bitset_t.c\
config_t.c\
dmlist_t.c\
@@ -37,7 +38,7 @@ SOURCES = $(UNITS)
endif
ifeq ("$(TESTING)", "yes")
-LDLIBS += -ldevmapper @CUNIT_LIBS@
+LDLIBS += $(LVMINTERNAL_LIBS) -ldevmapper -laio @CUNIT_LIBS@
CFLAGS += @CUNIT_CFLAGS@
check: unit
diff --git a/test/unit/bcache_t.c b/test/unit/bcache_t.c
new file mode 100644
index 0000000..da274a9
--- /dev/null
+++ b/test/unit/bcache_t.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "bcache.h"
+
+int bcache_init(void)
+{
+ return 0;
+}
+
+int bcache_fini(void)
+{
+ return 0;
+}
+
+static void test_create(void)
+{
+ struct bcache *cache = bcache_create(8, 16);
+ CU_ASSERT_PTR_NOT_NULL(cache);
+ bcache_destroy(cache);
+}
+
+CU_TestInfo bcache_list[] = {
+ { (char*)"create", test_create },
+ CU_TEST_INFO_NULL
+};
diff --git a/test/unit/run.c b/test/unit/run.c
index 7372138..82090ba 100644
--- a/test/unit/run.c
+++ b/test/unit/run.c
@@ -13,6 +13,7 @@
.pTests = n##_list }
CU_SuiteInfo suites[] = {
+ USE(bcache),
USE(bitset),
USE(config),
USE(dmlist),
diff --git a/test/unit/units.h b/test/unit/units.h
index 9eaa82f..319e7ce 100644
--- a/test/unit/units.h
+++ b/test/unit/units.h
@@ -23,6 +23,7 @@
int n ## _init(void); \
int n ## _fini(void);
+DECL(bcache);
DECL(bitset);
DECL(config);
DECL(dmlist);
6 years