Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ As a further extension, dm-writeboost supports read-caching which also writes da
* **Fast**: Since the sequential write is the best I/O pattern for every SSD and the code base is optimized for
in-coming random writes, the write performance is the best among all caching drivers including dm-cache and
bcache.
* **Portable**: All kernel version 3.10 or later is supported with minimum compile-time macros.
* **Portable**: Requires Linux kernel 4.18 or later.

## Usage
- **Install**: `sudo make install` to install and `sudo make uninstall` to uninstall.
Expand Down
4 changes: 2 additions & 2 deletions src/dkms.conf
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
PACKAGE_NAME="dm-writeboost"
PACKAGE_VERSION="2.2.19"

# dm-writeboost builds on top of dm features introduced in Linux 3.9
BUILD_EXCLUSIVE_KERNEL_MIN="3.9"
# Minimum supported Linux kernel version
BUILD_EXCLUSIVE_KERNEL_MIN="4.18"

BUILT_MODULE_NAME="dm-writeboost"
DEST_MODULE_LOCATION="/kernel/drivers/md"
Expand Down
14 changes: 7 additions & 7 deletions src/dm-writeboost-daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ static u32 calc_nr_writeback(struct wb_device *wb)
atomic64_read(&wb->last_flushed_segment_id)
- atomic64_read(&wb->last_writeback_segment_id);

u32 nr_max_batch = read_once(wb->nr_max_batched_writeback);
u32 nr_max_batch = READ_ONCE(wb->nr_max_batched_writeback);
if (wb->nr_writeback_segs != nr_max_batch)
try_alloc_writeback_ios(wb, nr_max_batch, GFP_NOIO | __GFP_NOWARN);

Expand All @@ -407,9 +407,9 @@ static u32 calc_nr_writeback(struct wb_device *wb)

static bool should_writeback(struct wb_device *wb)
{
return read_once(wb->allow_writeback) ||
read_once(wb->urge_writeback) ||
read_once(wb->force_drop);
return READ_ONCE(wb->allow_writeback) ||
READ_ONCE(wb->urge_writeback) ||
READ_ONCE(wb->force_drop);
}

static void do_writeback_proc(struct wb_device *wb)
Expand Down Expand Up @@ -494,7 +494,7 @@ int writeback_modulator_proc(void *data)

util = div_u64(100 * (new - old), 1000);

if (util < read_once(wb->writeback_threshold))
if (util < READ_ONCE(wb->writeback_threshold))
wb->allow_writeback = true;
else
wb->allow_writeback = false;
Expand Down Expand Up @@ -552,7 +552,7 @@ int sb_record_updater_proc(void *data)

while (!kthread_should_stop()) {
/* sec -> ms */
intvl = read_once(wb->update_sb_record_interval) * 1000;
intvl = READ_ONCE(wb->update_sb_record_interval) * 1000;

if (!intvl) {
schedule_timeout_interruptible(msecs_to_jiffies(1000));
Expand All @@ -574,7 +574,7 @@ int data_synchronizer_proc(void *data)

while (!kthread_should_stop()) {
/* sec -> ms */
intvl = read_once(wb->sync_data_interval) * 1000;
intvl = READ_ONCE(wb->sync_data_interval) * 1000;

if (!intvl) {
schedule_timeout_interruptible(msecs_to_jiffies(1000));
Expand Down
108 changes: 28 additions & 80 deletions src/dm-writeboost-target.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,31 +122,14 @@ sector_t dm_devsize(struct dm_dev *dev)

void bio_io_success_compat(struct bio *bio)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
bio->bi_status = BLK_STS_OK;
bio_endio(bio);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)
bio->bi_error = 0;
bio_endio(bio);
#else
bio_endio(bio, 0);
#endif
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
#define bi_sector(bio) (bio)->bi_iter.bi_sector
#else
#define bi_sector(bio) (bio)->bi_sector
#endif

static void bio_remap(struct bio *bio, struct dm_dev *dev, sector_t sector)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
bio_set_dev(bio, dev->bdev);
#else
bio->bi_bdev = dev->bdev;
#endif
bi_sector(bio) = sector;
bio->bi_iter.bi_sector = sector;
}

static u8 calc_offset(sector_t sector)
Expand All @@ -158,7 +141,7 @@ static u8 calc_offset(sector_t sector)

static u8 bio_calc_offset(struct bio *bio)
{
return calc_offset(bi_sector(bio));
return calc_offset(bio->bi_iter.bi_sector);
}

static bool bio_is_fullsize(struct bio *bio)
Expand Down Expand Up @@ -458,20 +441,6 @@ static void clear_stat(struct wb_device *wb)

/*----------------------------------------------------------------------------*/

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
#define bv_vec struct bio_vec
#define bv_page(vec) vec.bv_page
#define bv_offset(vec) vec.bv_offset
#define bv_len(vec) vec.bv_len
#define bv_it struct bvec_iter
#else
#define bv_vec struct bio_vec *
#define bv_page(vec) vec->bv_page
#define bv_offset(vec) vec->bv_offset
#define bv_len(vec) vec->bv_len
#define bv_it int
#endif

/*
* Incoming bio may have multiple bio vecs as a result bvec merging.
* We shouldn't use bio_data directly to access to whole payload but
Expand All @@ -480,12 +449,12 @@ static void clear_stat(struct wb_device *wb)
static void copy_bio_payload(void *buf, struct bio *bio)
{
size_t sum = 0;
bv_vec vec;
bv_it it;
struct bio_vec vec;
struct bvec_iter it;
bio_for_each_segment(vec, bio, it) {
void *dst = kmap_atomic(bv_page(vec));
size_t l = bv_len(vec);
memcpy(buf, dst + bv_offset(vec), l);
void *dst = kmap_atomic(vec.bv_page);
size_t l = vec.bv_len;
memcpy(buf, dst + vec.bv_offset, l);
kunmap_atomic(dst);
buf += l;
sum += l;
Expand All @@ -501,16 +470,16 @@ static void __copy_to_bio_payload(struct bio *bio, void *buf, u8 i)
size_t head = 0;
size_t tail = head;

bv_vec vec;
bv_it it;
struct bio_vec vec;
struct bvec_iter it;
bio_for_each_segment(vec, bio, it) {
size_t l = bv_len(vec);
size_t l = vec.bv_len;
tail += l;
if ((i << 9) < tail) {
void *dst = kmap_atomic(bv_page(vec));
void *dst = kmap_atomic(vec.bv_page);
size_t offset = (i << 9) - head;
BUG_ON((l - offset) < (1 << 9));
memcpy(dst + bv_offset(vec) + offset, buf, 1 << 9);
memcpy(dst + vec.bv_offset + offset, buf, 1 << 9);
kunmap_atomic(dst);
return;
}
Expand Down Expand Up @@ -553,7 +522,7 @@ struct lookup_result {
static void cache_lookup(struct wb_device *wb, struct bio *bio, struct lookup_result *res)
{
res->key = (struct lookup_key) {
.sector = calc_cache_alignment(bi_sector(bio)),
.sector = calc_cache_alignment(bio->bi_iter.bi_sector),
};
res->head = ht_get_head(wb, &res->key);

Expand Down Expand Up @@ -598,7 +567,7 @@ static int fill_payload_by_backing(struct wb_device *wb, struct bio *bio)
struct dm_io_request io_req;
struct dm_io_region region;

sector_t start = bi_sector(bio);
sector_t start = bio->bi_iter.bi_sector;
u8 offset = calc_offset(start);
u8 len = bio_sectors(bio);
u8 copy_bits = to_mask(offset, len);
Expand Down Expand Up @@ -691,11 +660,6 @@ enum PBD_FLAG {
PBD_READ_SEG = 2,
};

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) || RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3))
#define PER_BIO_DATA_SIZE per_io_data_size
#else
#define PER_BIO_DATA_SIZE per_bio_data_size
#endif
struct per_bio_data {
enum PBD_FLAG type;
union {
Expand Down Expand Up @@ -799,13 +763,13 @@ static bool do_reserve_read_cache_cell(struct read_cache_cells *cells, struct bi
* We don't need to reserve the same address twice
* because it's either unchanged or invalidated.
*/
found = lookup_read_cache_cell(cells, bi_sector(bio));
found = lookup_read_cache_cell(cells, bio->bi_iter.bi_sector);
if (found)
return false;

cells->cursor--;
new_cell = cells->array + cells->cursor;
new_cell->sector = bi_sector(bio);
new_cell->sector = bio->bi_iter.bi_sector;
read_cache_add(cells, new_cell);

/* Cancel the new_cell if needed */
Expand All @@ -820,7 +784,7 @@ static bool reserve_read_cache_cell(struct wb_device *wb, struct bio *bio)
struct read_cache_cells *cells = wb->read_cache_cells;
bool reserved;

if (!read_once(wb->read_cache_threshold))
if (!READ_ONCE(wb->read_cache_threshold))
return false;

/*
Expand Down Expand Up @@ -851,7 +815,7 @@ static void might_cancel_read_cache_cell(struct wb_device *wb, struct bio *bio)
struct read_cache_cells *cells = wb->read_cache_cells;

mutex_lock(&cells->lock);
found = lookup_read_cache_cell(cells, calc_cache_alignment(bi_sector(bio)));
found = lookup_read_cache_cell(cells, calc_cache_alignment(bio->bi_iter.bi_sector));
mutex_unlock(&cells->lock);

if (found)
Expand Down Expand Up @@ -1063,7 +1027,7 @@ static void read_cache_proc(struct work_struct *work)
}

mutex_lock(&cells->lock);
reinit_read_cache_cells(cells, read_once(wb->read_cache_threshold));
reinit_read_cache_cells(cells, READ_ONCE(wb->read_cache_threshold));
mutex_unlock(&cells->lock);
}

Expand Down Expand Up @@ -1278,7 +1242,7 @@ static int process_write_wa(struct wb_device *wb, struct bio *bio)
might_cancel_read_cache_cell(wb, bio);
mutex_unlock(&wb->io_lock);

bio_remap(bio, wb->backing_dev, bi_sector(bio));
bio_remap(bio, wb->backing_dev, bio->bi_iter.bi_sector);
return DM_MAPIO_REMAPPED;
}

Expand Down Expand Up @@ -1330,19 +1294,14 @@ static int read_backing_async(struct wb_device *wb, struct bio *bio)
io_req = (struct dm_io_request) {
WB_IO_READ,
.client = wb->io_client,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
.mem.type = DM_IO_BIO,
.mem.ptr.bio = bio,
#else
.mem.type = DM_IO_BVEC,
.mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx,
#endif
.notify.fn = read_backing_async_callback,
.notify.context = ctx
};
region = (struct dm_io_region) {
.bdev = wb->backing_dev->bdev,
.sector = bi_sector(bio),
.sector = bio->bi_iter.bi_sector,
.count = 8
};

Expand Down Expand Up @@ -1384,7 +1343,7 @@ static int process_read(struct wb_device *wb, struct bio *bio)
}
return DM_MAPIO_SUBMITTED;
} else {
bio_remap(bio, wb->backing_dev, bi_sector(bio));
bio_remap(bio, wb->backing_dev, bio->bi_iter.bi_sector);
return DM_MAPIO_REMAPPED;
}
}
Expand Down Expand Up @@ -1479,29 +1438,22 @@ static int writeboost_map(struct dm_target *ti, struct bio *bio)
}

/*
* DM_ENDIO_DONE was actually introduced since 4.12 but used restrictedly in rq-based dm.
* In 4.13, a patch titled "dm: change ->end_io calling convention" changed the dm internal
* so other bio-based dm targets should follow the convension.
* For this reason, I will start to use the DM_ENDIO_DONE at 4.13.
* DM_ENDIO_DONE was introduced in 4.12 for request-based dm.
* In 4.13, "dm: change ->end_io calling convention" extended this
* calling convention to bio-based dm targets.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
#define DM_ENDIO_DONE_COMPAT DM_ENDIO_DONE
static int writeboost_end_io(struct dm_target *ti, struct bio *bio, blk_status_t *error)
#else
#define DM_ENDIO_DONE_COMPAT 0
static int writeboost_end_io(struct dm_target *ti, struct bio *bio, int error)
#endif
{
struct wb_device *wb = ti->private;
struct per_bio_data *pbd = per_bio_data(bio);

switch (pbd->type) {
case PBD_NONE:
case PBD_WILL_CACHE:
return DM_ENDIO_DONE_COMPAT;
return DM_ENDIO_DONE;
case PBD_READ_SEG:
dec_inflight_ios(wb, pbd->seg);
return DM_ENDIO_DONE_COMPAT;
return DM_ENDIO_DONE;
default:
BUG();
}
Expand Down Expand Up @@ -1639,7 +1591,7 @@ static int init_core_struct(struct dm_target *ti)
ti->num_discard_bios = 0;
ti->discards_supported = false;

ti->PER_BIO_DATA_SIZE = sizeof(struct per_bio_data);
ti->per_io_data_size = sizeof(struct per_bio_data);

wb = kzalloc(sizeof(*wb), GFP_KERNEL);
if (!wb) {
Expand Down Expand Up @@ -1868,12 +1820,8 @@ static void writeboost_postsuspend(struct dm_target *ti)
dm_blkdev_issue_flush(wb->cache_dev->bdev, GFP_NOIO);
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
static int writeboost_message(struct dm_target *ti, unsigned argc, char **argv,
char *result, unsigned maxlen)
#else
static int writeboost_message(struct dm_target *ti, unsigned argc, char **argv)
#endif
{
struct wb_device *wb = ti->private;

Expand Down
23 changes: 1 addition & 22 deletions src/dm-writeboost.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@
#include <linux/dm-io.h>
#include <linux/dm-kcopyd.h>

/* We use RHEL_RELEASE_VERSION to compile with RHEL/CentOS 7.3's kernel */
#ifndef RHEL_RELEASE_CODE
#define RHEL_RELEASE_CODE 0
#define RHEL_RELEASE_VERSION(a,b) (((a) << 8) + (b))
#endif

/*----------------------------------------------------------------------------*/

#define SUB_ID(x, y) ((x) > (y) ? (x) - (y) : 0)
Expand Down Expand Up @@ -511,28 +505,13 @@ sector_t dm_devsize(struct dm_dev *);
#define WB_IO_WRITE_FUA .bi_opf = REQ_OP_WRITE | REQ_FUA
#define bio_is_barrier(bio) ((bio)->bi_opf & REQ_PREFLUSH)
#define bio_is_fua(bio) ((bio)->bi_opf & REQ_FUA)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0)
#else
#define req_is_write(req) op_is_write((req)->bi_op)
#define WB_IO_WRITE .bi_op = REQ_OP_WRITE, .bi_op_flags = 0
#define WB_IO_READ .bi_op = REQ_OP_READ, .bi_op_flags = 0
#define WB_IO_WRITE_FUA .bi_op = REQ_OP_WRITE, .bi_op_flags = REQ_FUA
#define bio_is_barrier(bio) ((bio)->bi_opf & REQ_PREFLUSH)
#define bio_is_fua(bio) ((bio)->bi_opf & REQ_FUA)
#else
#define req_is_write(req) ((req)->bi_rw == WRITE)
#define bio_is_barrier(bio) ((bio)->bi_rw & REQ_FLUSH)
#define bio_is_fua(bio) ((bio)->bi_rw & REQ_FUA)
#define WB_IO_WRITE .bi_rw = WRITE
#define WB_IO_READ .bi_rw = READ
#define WB_IO_WRITE_FUA .bi_rw = WRITE_FUA
#endif

/*----------------------------------------------------------------------------*/

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
#define read_once(x) READ_ONCE(x)
#else
#define read_once(x) ACCESS_ONCE(x)
#endif

/*----------------------------------------------------------------------------*/
Expand Down
Loading