Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/drivers/staging/writeboost/dm-writeboost-target.c b/drivers/staging/writeboost/dm-writeboost-target.c
- index 01349a5..b30227d 100644
- --- a/drivers/staging/writeboost/dm-writeboost-target.c
- +++ b/drivers/staging/writeboost/dm-writeboost-target.c
- @@ -990,6 +990,7 @@ static void dec_inflight_ios(struct wb_device *wb, struct segment_header *seg)
- * After returned, refcounts (in_flight_ios and in_flight_plog_writes)
- * are incremented.
- */
- +static void might_cancel_read_cache_cell(struct wb_device *, struct bio *);
- static void prepare_write_pos(struct wb_device *wb, struct bio *bio,
- struct write_job *pos)
- {
- @@ -1026,7 +1027,8 @@ static void prepare_write_pos(struct wb_device *wb, struct bio *bio,
- io_fullsize(bio));
- dec_inflight_ios(wb, res.found_seg);
- }
- - }
- + } else
- + might_cancel_read_cache_cell(wb, bio);
- prepare_new_pos(wb, bio, &res, pos);
- @@ -1131,10 +1133,21 @@ static int process_write(struct wb_device *wb, struct bio *bio)
- return process_write_job(wb, bio, job);
- }
- +enum PBD_FLAG {
- + PBD_NONE = 0,
- + PBD_WILL_CACHE = 1,
- + PBD_READ_SEG = 2,
- +};
- +
- struct per_bio_data {
- - void *ptr;
- + int type;
- + union {
- + u32 cell_idx;
- + struct segment_header *seg;
- + };
- };
- +static void reserve_read_cache_cell(struct wb_device *, struct bio *);
- static int process_read(struct wb_device *wb, struct bio *bio)
- {
- struct lookup_result res;
- @@ -1142,6 +1155,8 @@ static int process_read(struct wb_device *wb, struct bio *bio)
- mutex_lock(&wb->io_lock);
- cache_lookup(wb, bio, &res);
- + if (!res.found)
- + reserve_read_cache_cell(wb, bio);
- mutex_unlock(&wb->io_lock);
- if (!res.found) {
- @@ -1167,9 +1182,9 @@ static int process_read(struct wb_device *wb, struct bio *bio)
- wait_for_flushing(wb, res.found_seg->id);
- if (likely(dirty_bits == 255)) {
- - struct per_bio_data *map_context =
- - dm_per_bio_data(bio, wb->ti->per_bio_data_size);
- - map_context->ptr = res.found_seg;
- + struct per_bio_data *pbd = dm_per_bio_data(bio, wb->ti->per_bio_data_size);
- + pbd->type = PBD_READ_SEG;
- + pbd->seg = res.found_seg;
- bio_remap(bio, wb->cache_dev,
- calc_mb_start_sector(wb, res.found_seg, res.found_mb->idx) +
- @@ -1197,9 +1212,9 @@ static int writeboost_map(struct dm_target *ti, struct bio *bio)
- {
- struct wb_device *wb = ti->private;
- - struct per_bio_data *map_context;
- - map_context = dm_per_bio_data(bio, ti->per_bio_data_size);
- - map_context->ptr = NULL;
- + struct per_bio_data *pbd;
- + pbd = dm_per_bio_data(bio, ti->per_bio_data_size);
- + pbd->type = PBD_NONE;
- if (bio->bi_rw & REQ_DISCARD)
- return process_discard_bio(wb, bio);
- @@ -1210,18 +1225,245 @@ static int writeboost_map(struct dm_target *ti, struct bio *bio)
- return process_bio(wb, bio);
- }
- +static void read_cache_cell_copy_data(struct wb_device *, struct bio*);
- static int writeboost_end_io(struct dm_target *ti, struct bio *bio, int error)
- {
- struct wb_device *wb = ti->private;
- - struct per_bio_data *map_context =
- - dm_per_bio_data(bio, ti->per_bio_data_size);
- - struct segment_header *seg;
- + struct per_bio_data *pbd = dm_per_bio_data(bio, ti->per_bio_data_size);
- - if (!map_context->ptr)
- + switch (pbd->type) {
- + case PBD_NONE:
- + return 0;
- + case PBD_WILL_CACHE:
- + read_cache_cell_copy_data(wb, bio);
- + return 0;
- + case PBD_READ_SEG:
- + dec_inflight_ios(wb, pbd->seg);
- return 0;
- + default:
- + BUG();
- + }
- + BUG();
- +}
- +
- +/*----------------------------------------------------------------*/
- +
- +static struct read_cache_cell *lookup_read_cache_cell(struct wb_device *wb, sector_t sector)
- +{
- + struct read_cache_cells *cells = wb->read_cache_cells;
- + u32 i;
- + for (i = 0; i < cells->size; i++) {
- + struct read_cache_cell *cell = cells->array + i;
- + if (cell->sector == sector)
- + return cell;
- + }
- + return NULL;
- +}
- +
- +static void reserve_read_cache_cell(struct wb_device *wb, struct bio *bio)
- +{
- + struct per_bio_data *pbd;
- + struct read_cache_cells *cells = wb->read_cache_cells;
- + struct read_cache_cell *found, *new_cell;
- +
- + if (!ACCESS_ONCE(wb->read_cache_threshold))
- + return;
- +
- + if (!cells->cursor)
- + return;
- +
- + /*
- + * We cache 4KB read data only for following reasons:
- + * 1) Caching partial data (< 4KB) is likely meaningless.
- + * 2) Caching partial data makes the read-caching mechanism very hard.
- + */
- + if (!io_fullsize(bio))
- + return;
- +
- + /*
- + * We don't need to reserve the same adress twice
- + * because it's either unchanged or invalidated.
- + */
- + found = lookup_read_cache_cell(wb, bio->bi_iter.bi_sector);
- + if (found)
- + return;
- +
- + cells->cursor--;
- + new_cell = cells->array + cells->cursor;
- + new_cell->sector = bio_sectors(bio);
- +
- + pbd = dm_per_bio_data(bio, wb->ti->per_bio_data_size);
- + pbd->type = PBD_WILL_CACHE;
- + pbd->cell_idx = cells->cursor;
- +}
- +
- +static void might_cancel_read_cache_cell(struct wb_device *wb, struct bio *bio)
- +{
- + struct read_cache_cell *found;
- + found = lookup_read_cache_cell(wb, calc_cache_alignment(bio->bi_iter.bi_sector));
- + if (found)
- + found->cancelled = true;
- +}
- +
- +static void read_cache_cell_copy_data(struct wb_device *wb, struct bio *bio)
- +{
- + struct per_bio_data *pbd = dm_per_bio_data(bio, wb->ti->per_bio_data_size);
- + struct read_cache_cells *cells = wb->read_cache_cells;
- + struct read_cache_cell *cell = cells->array + pbd->cell_idx;
- +
- + /*
- + * If the cell is cancelled for some reason such as being stale or
- + * part of sequential read more than threshold memcpy can be skipped.
- + */
- + if (!ACCESS_ONCE(cell->cancelled))
- + memcpy(cell->data, bio_data(bio), 1 << 12);
- +
- + if (atomic_dec_and_test(&cells->ack_count))
- + schedule_work(&wb->read_cache_work);
- +}
- +
- +/*
- + * Get a read cache cell through simplified write path if the cell data isn't stale.
- + */
- +static void inject_read_cache(struct wb_device *wb, struct read_cache_cell *cell)
- +{
- + struct metablock *mb;
- + struct segment_header *seg;
- + u32 mb_idx;
- +
- + struct lookup_key key = {
- + .sector = cell->sector,
- + };
- +
- + if (ACCESS_ONCE(cell->cancelled))
- + return;
- - seg = map_context->ptr;
- - dec_inflight_ios(wb, seg);
- + mutex_lock(&wb->io_lock);
- + if (!mb_idx_inseg(wb, wb->cursor))
- + queue_current_buffer(wb);
- + mb = ht_lookup(wb, ht_get_head(wb, &key), &key);
- + if (unlikely(mb)) {
- + /*
- + * Entering here will cause calling queue_current_buffer() again in the next
- + * iteration but it's really rare given that the cell wasn't found cancelled.
- + */
- + mutex_unlock(&wb->io_lock);
- + return;
- + }
- + seg = wb->current_seg;
- + mb_idx = mb_idx_inseg(wb, advance_cursor(wb));
- + atomic_inc(&seg->nr_inflight_ios);
- + mutex_unlock(&wb->io_lock);
- +
- + memcpy(wb->current_rambuf + ((mb_idx + 1) << 12), cell->data, 1 << 12);
- + atomic_dec(&seg->nr_inflight_ios);
- +}
- +
- +static struct read_cache_cells *alloc_read_cache_cells(struct wb_device *wb, u32 n)
- +{
- + struct read_cache_cells *cells;
- + u32 i;
- + cells = kmalloc(sizeof(struct read_cache_cells), GFP_KERNEL);
- + if (!cells)
- + return NULL;
- +
- + cells->size = n;
- + cells->threshold = n / 2;
- + cells->array = kmalloc(sizeof(struct read_cache_cell) * n, GFP_KERNEL);
- + if (!cells->array)
- + goto bad_cells_array;
- +
- + for (i = 0; i < cells->size; i++) {
- + struct read_cache_cell *cell = cells->array + i;
- + cell->data = kmalloc(1 << 12, GFP_KERNEL);
- + if (!cell->data) {
- + u32 j;
- + for (j = 0; j < i; j++) {
- + cell = cells->array + j;
- + kfree(cell->data);
- + }
- + goto bad_cell_data;
- + }
- + }
- + return cells;
- +
- +bad_cell_data:
- + kfree(cells->array);
- +bad_cells_array:
- + kfree(cells);
- + return NULL;
- +}
- +
- +static void free_read_cache_cells(struct wb_device *wb)
- +{
- + struct read_cache_cells *cells = wb->read_cache_cells;
- + u32 i;
- + for (i = 0; i < cells->size; i++) {
- + struct read_cache_cell *cell = cells->array + i;
- + kfree(cell->data);
- + }
- + kfree(cells->array);
- + kfree(cells);
- +}
- +
- +static void might_realloc_read_cache_cells(struct wb_device *);
- +static void reinit_read_cache_cells(struct wb_device *wb)
- +{
- + struct read_cache_cells *cells;
- + u32 i;
- + cells = wb->read_cache_cells;
- + for (i = 0; i < cells->size; i++) {
- + struct read_cache_cell *cell = cells->array + i;
- + cell->cancelled = false;
- + }
- + atomic_set(&cells->ack_count, cells->size);
- +
- + mutex_lock(&wb->io_lock);
- + cells->cursor = cells->size;
- + might_realloc_read_cache_cells(wb);
- + mutex_unlock(&wb->io_lock);
- +}
- +
- +static void might_realloc_read_cache_cells(struct wb_device *wb)
- +{
- + struct read_cache_cells *cells, *new_cells;
- + u32 cur_threshold;
- +
- + cells = wb->read_cache_cells;
- + cur_threshold = ACCESS_ONCE(wb->read_cache_threshold);
- + if (!cur_threshold && (cells->threshold != cur_threshold))
- + return;
- +
- + new_cells = alloc_read_cache_cells(wb, cur_threshold * 2);
- + if (!new_cells)
- + return;
- + wb->read_cache_cells = new_cells;
- + reinit_read_cache_cells(wb);
- +}
- +
- +static void read_cache_proc(struct work_struct *work)
- +{
- + struct wb_device *wb = container_of(work, struct wb_device, read_cache_work);
- + struct read_cache_cells *cells = wb->read_cache_cells;
- +
- + u32 i;
- + for (i = 0; i < cells->size; i++) {
- + struct read_cache_cell *cell = cells->array + i;
- + inject_read_cache(wb, cell);
- + }
- + reinit_read_cache_cells(wb);
- +}
- +
- +static int init_read_cache_cells(struct wb_device *wb)
- +{
- + struct read_cache_cells *cells;
- + wb->read_cache_threshold = 0; /* Default: read-caching disabled */
- + cells = alloc_read_cache_cells(wb, 1);
- + if (!cells)
- + return -ENOMEM;
- + wb->read_cache_cells = cells;
- + INIT_WORK(&wb->read_cache_work, read_cache_proc);
- + reinit_read_cache_cells(wb);
- return 0;
- }
- @@ -1336,6 +1578,7 @@ static int do_consume_tunable_argv(struct wb_device *wb,
- {0, 100, "Invalid writeback_threshold"},
- {0, 3600, "Invalid update_record_interval"},
- {0, 3600, "Invalid sync_interval"},
- + {0, 128, "Invalid read_cache_threshold"},
- };
- unsigned tmp;
- @@ -1351,6 +1594,7 @@ static int do_consume_tunable_argv(struct wb_device *wb,
- consume_kv(writeback_threshold, 3);
- consume_kv(update_record_interval, 4);
- consume_kv(sync_interval, 5);
- + consume_kv(read_cache_threshold, 6);
- if (!r) {
- argc--;
- @@ -1564,11 +1808,18 @@ static int writeboost_ctr(struct dm_target *ti, unsigned int argc, char **argv)
- goto bad_tunable_argv;
- }
- + r = init_read_cache_cells(wb);
- + if (r) {
- + ti->error = "init_read_cache_cells failed";
- + goto bad_read_cache_cells;
- + }
- +
- clear_stat(wb);
- atomic64_set(&wb->count_non_full_flushed, 0);
- return r;
- +bad_read_cache_cells:
- bad_tunable_argv:
- free_cache(wb);
- bad_resume_cache:
- @@ -1586,6 +1837,8 @@ static void writeboost_dtr(struct dm_target *ti)
- {
- struct wb_device *wb = ti->private;
- + free_read_cache_cells(wb);
- +
- free_cache(wb);
- dm_put_device(ti, wb->cache_dev);
- @@ -1658,7 +1911,7 @@ static void emit_tunables(struct wb_device *wb, char *result, unsigned maxlen)
- {
- ssize_t sz = 0;
- - DMEMIT(" %d", 12);
- + DMEMIT(" %d", 14);
- DMEMIT(" allow_writeback %d",
- wb->allow_writeback ? 1 : 0);
- DMEMIT(" enable_writeback_modulator %d",
- @@ -1671,6 +1924,8 @@ static void emit_tunables(struct wb_device *wb, char *result, unsigned maxlen)
- wb->sync_interval);
- DMEMIT(" update_record_interval %lu",
- wb->update_record_interval);
- + DMEMIT(" read_cache_threshold %u",
- + wb->read_cache_threshold);
- }
- static void writeboost_status(struct dm_target *ti, status_type_t type,
- diff --git a/drivers/staging/writeboost/dm-writeboost.h b/drivers/staging/writeboost/dm-writeboost.h
- index 05e52f4..9b4ada3 100644
- --- a/drivers/staging/writeboost/dm-writeboost.h
- +++ b/drivers/staging/writeboost/dm-writeboost.h
- @@ -254,6 +254,22 @@ struct writeback_segment {
- /*----------------------------------------------------------------*/
- +struct read_cache_cell {
- + sector_t sector;
- + void *data;
- + int cancelled; /* Don't include this */
- +};
- +
- +struct read_cache_cells {
- + u32 size;
- + u32 threshold;
- + struct read_cache_cell *array;
- + u32 cursor;
- + atomic_t ack_count;
- +};
- +
- +/*----------------------------------------------------------------*/
- +
- enum STATFLAG {
- STAT_WRITE = 3, /* Write or read */
- STAT_HIT = 2, /* Hit or miss */
- @@ -466,6 +482,16 @@ struct wb_device {
- /*---------------------------------------------*/
- + /**************
- + * Read Caching
- + **************/
- +
- + struct work_struct read_cache_work;
- + struct read_cache_cells *read_cache_cells;
- + u32 read_cache_threshold;
- +
- + /*---------------------------------------------*/
- +
- /********************
- * Persistent Logging
- ********************/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement