mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'for-4.15/block' of git://git.kernel.dk/linux-block
Pull core block layer updates from Jens Axboe:
"This is the main pull request for block storage for 4.15-rc1.
Nothing out of the ordinary in here, and no API changes or anything
like that. Just various new features for drivers, core changes, etc.
In particular, this pull request contains:
- A patch series from Bart, closing the whole on blk/scsi-mq queue
quescing.
- A series from Christoph, building towards hidden gendisks (for
multipath) and ability to move bio chains around.
- NVMe
- Support for native multipath for NVMe (Christoph).
- Userspace notifications for AENs (Keith).
- Command side-effects support (Keith).
- SGL support (Chaitanya Kulkarni)
- FC fixes and improvements (James Smart)
- Lots of fixes and tweaks (Various)
- bcache
- New maintainer (Michael Lyle)
- Writeback control improvements (Michael)
- Various fixes (Coly, Elena, Eric, Liang, et al)
- lightnvm updates, mostly centered around the pblk interface
(Javier, Hans, and Rakesh).
- Removal of unused bio/bvec kmap atomic interfaces (me, Christoph)
- Writeback series that fix the much discussed hundreds of millions
of sync-all units. This goes all the way, as discussed previously
(me).
- Fix for missing wakeup on writeback timer adjustments (Yafang
Shao).
- Fix laptop mode on blk-mq (me).
- {mq,name} tupple lookup for IO schedulers, allowing us to have
alias names. This means you can use 'deadline' on both !mq and on
mq (where it's called mq-deadline). (me).
- blktrace race fix, oopsing on sg load (me).
- blk-mq optimizations (me).
- Obscure waitqueue race fix for kyber (Omar).
- NBD fixes (Josef).
- Disable writeback throttling by default on bfq, like we do on cfq
(Luca Miccio).
- Series from Ming that enable us to treat flush requests on blk-mq
like any other request. This is a really nice cleanup.
- Series from Ming that improves merging on blk-mq with schedulers,
getting us closer to flipping the switch on scsi-mq again.
- BFQ updates (Paolo).
- blk-mq atomic flags memory ordering fixes (Peter Z).
- Loop cgroup support (Shaohua).
- Lots of minor fixes from lots of different folks, both for core and
driver code"
* 'for-4.15/block' of git://git.kernel.dk/linux-block: (294 commits)
nvme: fix visibility of "uuid" ns attribute
blk-mq: fixup some comment typos and lengths
ide: ide-atapi: fix compile error with defining macro DEBUG
blk-mq: improve tag waiting setup for non-shared tags
brd: remove unused brd_mutex
blk-mq: only run the hardware queue if IO is pending
block: avoid null pointer dereference on null disk
fs: guard_bio_eod() needs to consider partitions
xtensa/simdisk: fix compile error
nvme: expose subsys attribute to sysfs
nvme: create 'slaves' and 'holders' entries for hidden controllers
block: create 'slaves' and 'holders' entries for hidden gendisks
nvme: also expose the namespace identification sysfs files for mpath nodes
nvme: implement multipath access to nvme subsystems
nvme: track shared namespaces
nvme: introduce a nvme_ns_ids structure
nvme: track subsystems
block, nvme: Introduce blk_mq_req_flags_t
block, scsi: Make SCSI quiesce and resume work reliably
block: Add the QUEUE_FLAG_PREEMPT_ONLY request queue flag
...
This commit is contained in:
commit
e2c5923c34
131 changed files with 5470 additions and 3089 deletions
|
|
@ -407,7 +407,8 @@ long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait)
|
|||
|
||||
finish_wait(&ca->set->bucket_wait, &w);
|
||||
out:
|
||||
wake_up_process(ca->alloc_thread);
|
||||
if (ca->alloc_thread)
|
||||
wake_up_process(ca->alloc_thread);
|
||||
|
||||
trace_bcache_alloc(ca, reserve);
|
||||
|
||||
|
|
@ -442,6 +443,11 @@ out:
|
|||
b->prio = INITIAL_PRIO;
|
||||
}
|
||||
|
||||
if (ca->set->avail_nbuckets > 0) {
|
||||
ca->set->avail_nbuckets--;
|
||||
bch_update_bucket_in_use(ca->set, &ca->set->gc_stats);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -449,6 +455,11 @@ void __bch_bucket_free(struct cache *ca, struct bucket *b)
|
|||
{
|
||||
SET_GC_MARK(b, 0);
|
||||
SET_GC_SECTORS_USED(b, 0);
|
||||
|
||||
if (ca->set->avail_nbuckets < ca->set->nbuckets) {
|
||||
ca->set->avail_nbuckets++;
|
||||
bch_update_bucket_in_use(ca->set, &ca->set->gc_stats);
|
||||
}
|
||||
}
|
||||
|
||||
void bch_bucket_free(struct cache_set *c, struct bkey *k)
|
||||
|
|
@ -601,7 +612,7 @@ bool bch_alloc_sectors(struct cache_set *c, struct bkey *k, unsigned sectors,
|
|||
|
||||
/*
|
||||
* If we had to allocate, we might race and not need to allocate the
|
||||
* second time we call find_data_bucket(). If we allocated a bucket but
|
||||
* second time we call pick_data_bucket(). If we allocated a bucket but
|
||||
* didn't use it, drop the refcount bch_bucket_alloc_set() took:
|
||||
*/
|
||||
if (KEY_PTRS(&alloc.key))
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
|
|
@ -266,9 +267,6 @@ struct bcache_device {
|
|||
atomic_t *stripe_sectors_dirty;
|
||||
unsigned long *full_dirty_stripes;
|
||||
|
||||
unsigned long sectors_dirty_last;
|
||||
long sectors_dirty_derivative;
|
||||
|
||||
struct bio_set *bio_split;
|
||||
|
||||
unsigned data_csum:1;
|
||||
|
|
@ -300,7 +298,7 @@ struct cached_dev {
|
|||
struct semaphore sb_write_mutex;
|
||||
|
||||
/* Refcount on the cache set. Always nonzero when we're caching. */
|
||||
atomic_t count;
|
||||
refcount_t count;
|
||||
struct work_struct detach;
|
||||
|
||||
/*
|
||||
|
|
@ -363,12 +361,14 @@ struct cached_dev {
|
|||
|
||||
uint64_t writeback_rate_target;
|
||||
int64_t writeback_rate_proportional;
|
||||
int64_t writeback_rate_derivative;
|
||||
int64_t writeback_rate_change;
|
||||
int64_t writeback_rate_integral;
|
||||
int64_t writeback_rate_integral_scaled;
|
||||
int32_t writeback_rate_change;
|
||||
|
||||
unsigned writeback_rate_update_seconds;
|
||||
unsigned writeback_rate_d_term;
|
||||
unsigned writeback_rate_i_term_inverse;
|
||||
unsigned writeback_rate_p_term_inverse;
|
||||
unsigned writeback_rate_minimum;
|
||||
};
|
||||
|
||||
enum alloc_reserve {
|
||||
|
|
@ -582,6 +582,7 @@ struct cache_set {
|
|||
uint8_t need_gc;
|
||||
struct gc_stat gc_stats;
|
||||
size_t nbuckets;
|
||||
size_t avail_nbuckets;
|
||||
|
||||
struct task_struct *gc_thread;
|
||||
/* Where in the btree gc currently is */
|
||||
|
|
@ -807,13 +808,13 @@ do { \
|
|||
|
||||
static inline void cached_dev_put(struct cached_dev *dc)
|
||||
{
|
||||
if (atomic_dec_and_test(&dc->count))
|
||||
if (refcount_dec_and_test(&dc->count))
|
||||
schedule_work(&dc->detach);
|
||||
}
|
||||
|
||||
static inline bool cached_dev_get(struct cached_dev *dc)
|
||||
{
|
||||
if (!atomic_inc_not_zero(&dc->count))
|
||||
if (!refcount_inc_not_zero(&dc->count))
|
||||
return false;
|
||||
|
||||
/* Paired with the mb in cached_dev_attach */
|
||||
|
|
|
|||
|
|
@ -1241,6 +1241,11 @@ void bch_initial_mark_key(struct cache_set *c, int level, struct bkey *k)
|
|||
__bch_btree_mark_key(c, level, k);
|
||||
}
|
||||
|
||||
void bch_update_bucket_in_use(struct cache_set *c, struct gc_stat *stats)
|
||||
{
|
||||
stats->in_use = (c->nbuckets - c->avail_nbuckets) * 100 / c->nbuckets;
|
||||
}
|
||||
|
||||
static bool btree_gc_mark_node(struct btree *b, struct gc_stat *gc)
|
||||
{
|
||||
uint8_t stale = 0;
|
||||
|
|
@ -1652,9 +1657,8 @@ static void btree_gc_start(struct cache_set *c)
|
|||
mutex_unlock(&c->bucket_lock);
|
||||
}
|
||||
|
||||
static size_t bch_btree_gc_finish(struct cache_set *c)
|
||||
static void bch_btree_gc_finish(struct cache_set *c)
|
||||
{
|
||||
size_t available = 0;
|
||||
struct bucket *b;
|
||||
struct cache *ca;
|
||||
unsigned i;
|
||||
|
|
@ -1691,6 +1695,7 @@ static size_t bch_btree_gc_finish(struct cache_set *c)
|
|||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
c->avail_nbuckets = 0;
|
||||
for_each_cache(ca, c, i) {
|
||||
uint64_t *i;
|
||||
|
||||
|
|
@ -1712,18 +1717,16 @@ static size_t bch_btree_gc_finish(struct cache_set *c)
|
|||
BUG_ON(!GC_MARK(b) && GC_SECTORS_USED(b));
|
||||
|
||||
if (!GC_MARK(b) || GC_MARK(b) == GC_MARK_RECLAIMABLE)
|
||||
available++;
|
||||
c->avail_nbuckets++;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&c->bucket_lock);
|
||||
return available;
|
||||
}
|
||||
|
||||
static void bch_btree_gc(struct cache_set *c)
|
||||
{
|
||||
int ret;
|
||||
unsigned long available;
|
||||
struct gc_stat stats;
|
||||
struct closure writes;
|
||||
struct btree_op op;
|
||||
|
|
@ -1746,14 +1749,14 @@ static void bch_btree_gc(struct cache_set *c)
|
|||
pr_warn("gc failed!");
|
||||
} while (ret);
|
||||
|
||||
available = bch_btree_gc_finish(c);
|
||||
bch_btree_gc_finish(c);
|
||||
wake_up_allocators(c);
|
||||
|
||||
bch_time_stats_update(&c->btree_gc_time, start_time);
|
||||
|
||||
stats.key_bytes *= sizeof(uint64_t);
|
||||
stats.data <<= 9;
|
||||
stats.in_use = (c->nbuckets - available) * 100 / c->nbuckets;
|
||||
bch_update_bucket_in_use(c, &stats);
|
||||
memcpy(&c->gc_stats, &stats, sizeof(struct gc_stat));
|
||||
|
||||
trace_bcache_gc_end(c);
|
||||
|
|
|
|||
|
|
@ -306,5 +306,5 @@ void bch_keybuf_del(struct keybuf *, struct keybuf_key *);
|
|||
struct keybuf_key *bch_keybuf_next(struct keybuf *);
|
||||
struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *, struct keybuf *,
|
||||
struct bkey *, keybuf_pred_fn *);
|
||||
|
||||
void bch_update_bucket_in_use(struct cache_set *c, struct gc_stat *stats);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -252,6 +252,12 @@ static inline void set_closure_fn(struct closure *cl, closure_fn *fn,
|
|||
static inline void closure_queue(struct closure *cl)
|
||||
{
|
||||
struct workqueue_struct *wq = cl->wq;
|
||||
/**
|
||||
* Changes made to closure, work_struct, or a couple of other structs
|
||||
* may cause work.func not pointing to the right location.
|
||||
*/
|
||||
BUILD_BUG_ON(offsetof(struct closure, fn)
|
||||
!= offsetof(struct work_struct, func));
|
||||
if (wq) {
|
||||
INIT_WORK(&cl->work, cl->work.func);
|
||||
BUG_ON(!queue_work(wq, &cl->work));
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ struct kmem_cache *bch_search_cache;
|
|||
|
||||
static void bch_data_insert_start(struct closure *);
|
||||
|
||||
static unsigned cache_mode(struct cached_dev *dc, struct bio *bio)
|
||||
static unsigned cache_mode(struct cached_dev *dc)
|
||||
{
|
||||
return BDEV_CACHE_MODE(&dc->sb);
|
||||
}
|
||||
|
||||
static bool verify(struct cached_dev *dc, struct bio *bio)
|
||||
static bool verify(struct cached_dev *dc)
|
||||
{
|
||||
return dc->verify;
|
||||
}
|
||||
|
|
@ -370,7 +370,7 @@ static struct hlist_head *iohash(struct cached_dev *dc, uint64_t k)
|
|||
static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
|
||||
{
|
||||
struct cache_set *c = dc->disk.c;
|
||||
unsigned mode = cache_mode(dc, bio);
|
||||
unsigned mode = cache_mode(dc);
|
||||
unsigned sectors, congested = bch_get_congested(c);
|
||||
struct task_struct *task = current;
|
||||
struct io *i;
|
||||
|
|
@ -385,6 +385,14 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
|
|||
op_is_write(bio_op(bio))))
|
||||
goto skip;
|
||||
|
||||
/*
|
||||
* Flag for bypass if the IO is for read-ahead or background,
|
||||
* unless the read-ahead request is for metadata (eg, for gfs2).
|
||||
*/
|
||||
if (bio->bi_opf & (REQ_RAHEAD|REQ_BACKGROUND) &&
|
||||
!(bio->bi_opf & REQ_META))
|
||||
goto skip;
|
||||
|
||||
if (bio->bi_iter.bi_sector & (c->sb.block_size - 1) ||
|
||||
bio_sectors(bio) & (c->sb.block_size - 1)) {
|
||||
pr_debug("skipping unaligned io");
|
||||
|
|
@ -463,6 +471,7 @@ struct search {
|
|||
unsigned recoverable:1;
|
||||
unsigned write:1;
|
||||
unsigned read_dirty_data:1;
|
||||
unsigned cache_missed:1;
|
||||
|
||||
unsigned long start_time;
|
||||
|
||||
|
|
@ -649,6 +658,7 @@ static inline struct search *search_alloc(struct bio *bio,
|
|||
|
||||
s->orig_bio = bio;
|
||||
s->cache_miss = NULL;
|
||||
s->cache_missed = 0;
|
||||
s->d = d;
|
||||
s->recoverable = 1;
|
||||
s->write = op_is_write(bio_op(bio));
|
||||
|
|
@ -698,8 +708,16 @@ static void cached_dev_read_error(struct closure *cl)
|
|||
{
|
||||
struct search *s = container_of(cl, struct search, cl);
|
||||
struct bio *bio = &s->bio.bio;
|
||||
struct cached_dev *dc = container_of(s->d, struct cached_dev, disk);
|
||||
|
||||
if (s->recoverable) {
|
||||
/*
|
||||
* If cache device is dirty (dc->has_dirty is non-zero), then
|
||||
* recovery a failed read request from cached device may get a
|
||||
* stale data back. So read failure recovery is only permitted
|
||||
* when cache device is clean.
|
||||
*/
|
||||
if (s->recoverable &&
|
||||
(dc && !atomic_read(&dc->has_dirty))) {
|
||||
/* Retry from the backing device: */
|
||||
trace_bcache_read_retry(s->orig_bio);
|
||||
|
||||
|
|
@ -740,7 +758,7 @@ static void cached_dev_read_done(struct closure *cl)
|
|||
s->cache_miss = NULL;
|
||||
}
|
||||
|
||||
if (verify(dc, &s->bio.bio) && s->recoverable && !s->read_dirty_data)
|
||||
if (verify(dc) && s->recoverable && !s->read_dirty_data)
|
||||
bch_data_verify(dc, s->orig_bio);
|
||||
|
||||
bio_complete(s);
|
||||
|
|
@ -760,12 +778,12 @@ static void cached_dev_read_done_bh(struct closure *cl)
|
|||
struct cached_dev *dc = container_of(s->d, struct cached_dev, disk);
|
||||
|
||||
bch_mark_cache_accounting(s->iop.c, s->d,
|
||||
!s->cache_miss, s->iop.bypass);
|
||||
!s->cache_missed, s->iop.bypass);
|
||||
trace_bcache_read(s->orig_bio, !s->cache_miss, s->iop.bypass);
|
||||
|
||||
if (s->iop.status)
|
||||
continue_at_nobarrier(cl, cached_dev_read_error, bcache_wq);
|
||||
else if (s->iop.bio || verify(dc, &s->bio.bio))
|
||||
else if (s->iop.bio || verify(dc))
|
||||
continue_at_nobarrier(cl, cached_dev_read_done, bcache_wq);
|
||||
else
|
||||
continue_at_nobarrier(cl, cached_dev_bio_complete, NULL);
|
||||
|
|
@ -779,6 +797,8 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
|
|||
struct cached_dev *dc = container_of(s->d, struct cached_dev, disk);
|
||||
struct bio *miss, *cache_bio;
|
||||
|
||||
s->cache_missed = 1;
|
||||
|
||||
if (s->cache_miss || s->iop.bypass) {
|
||||
miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split);
|
||||
ret = miss == bio ? MAP_DONE : MAP_CONTINUE;
|
||||
|
|
@ -892,7 +912,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s)
|
|||
s->iop.bypass = true;
|
||||
|
||||
if (should_writeback(dc, s->orig_bio,
|
||||
cache_mode(dc, bio),
|
||||
cache_mode(dc),
|
||||
s->iop.bypass)) {
|
||||
s->iop.bypass = false;
|
||||
s->iop.writeback = true;
|
||||
|
|
|
|||
|
|
@ -53,12 +53,15 @@ LIST_HEAD(bch_cache_sets);
|
|||
static LIST_HEAD(uncached_devices);
|
||||
|
||||
static int bcache_major;
|
||||
static DEFINE_IDA(bcache_minor);
|
||||
static DEFINE_IDA(bcache_device_idx);
|
||||
static wait_queue_head_t unregister_wait;
|
||||
struct workqueue_struct *bcache_wq;
|
||||
|
||||
#define BTREE_MAX_PAGES (256 * 1024 / PAGE_SIZE)
|
||||
#define BCACHE_MINORS 16 /* partition support */
|
||||
/* limitation of partitions number on single bcache device */
|
||||
#define BCACHE_MINORS 128
|
||||
/* limitation of bcache devices number on single system */
|
||||
#define BCACHE_DEVICE_IDX_MAX ((1U << MINORBITS)/BCACHE_MINORS)
|
||||
|
||||
/* Superblock */
|
||||
|
||||
|
|
@ -721,6 +724,16 @@ static void bcache_device_attach(struct bcache_device *d, struct cache_set *c,
|
|||
closure_get(&c->caching);
|
||||
}
|
||||
|
||||
static inline int first_minor_to_idx(int first_minor)
|
||||
{
|
||||
return (first_minor/BCACHE_MINORS);
|
||||
}
|
||||
|
||||
static inline int idx_to_first_minor(int idx)
|
||||
{
|
||||
return (idx * BCACHE_MINORS);
|
||||
}
|
||||
|
||||
static void bcache_device_free(struct bcache_device *d)
|
||||
{
|
||||
lockdep_assert_held(&bch_register_lock);
|
||||
|
|
@ -734,7 +747,8 @@ static void bcache_device_free(struct bcache_device *d)
|
|||
if (d->disk && d->disk->queue)
|
||||
blk_cleanup_queue(d->disk->queue);
|
||||
if (d->disk) {
|
||||
ida_simple_remove(&bcache_minor, d->disk->first_minor);
|
||||
ida_simple_remove(&bcache_device_idx,
|
||||
first_minor_to_idx(d->disk->first_minor));
|
||||
put_disk(d->disk);
|
||||
}
|
||||
|
||||
|
|
@ -751,7 +765,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
|
|||
{
|
||||
struct request_queue *q;
|
||||
size_t n;
|
||||
int minor;
|
||||
int idx;
|
||||
|
||||
if (!d->stripe_size)
|
||||
d->stripe_size = 1 << 31;
|
||||
|
|
@ -776,25 +790,24 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
|
|||
if (!d->full_dirty_stripes)
|
||||
return -ENOMEM;
|
||||
|
||||
minor = ida_simple_get(&bcache_minor, 0, MINORMASK + 1, GFP_KERNEL);
|
||||
if (minor < 0)
|
||||
return minor;
|
||||
|
||||
minor *= BCACHE_MINORS;
|
||||
idx = ida_simple_get(&bcache_device_idx, 0,
|
||||
BCACHE_DEVICE_IDX_MAX, GFP_KERNEL);
|
||||
if (idx < 0)
|
||||
return idx;
|
||||
|
||||
if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio),
|
||||
BIOSET_NEED_BVECS |
|
||||
BIOSET_NEED_RESCUER)) ||
|
||||
!(d->disk = alloc_disk(BCACHE_MINORS))) {
|
||||
ida_simple_remove(&bcache_minor, minor);
|
||||
ida_simple_remove(&bcache_device_idx, idx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
set_capacity(d->disk, sectors);
|
||||
snprintf(d->disk->disk_name, DISK_NAME_LEN, "bcache%i", minor);
|
||||
snprintf(d->disk->disk_name, DISK_NAME_LEN, "bcache%i", idx);
|
||||
|
||||
d->disk->major = bcache_major;
|
||||
d->disk->first_minor = minor;
|
||||
d->disk->first_minor = idx_to_first_minor(idx);
|
||||
d->disk->fops = &bcache_ops;
|
||||
d->disk->private_data = d;
|
||||
|
||||
|
|
@ -889,7 +902,7 @@ static void cached_dev_detach_finish(struct work_struct *w)
|
|||
closure_init_stack(&cl);
|
||||
|
||||
BUG_ON(!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags));
|
||||
BUG_ON(atomic_read(&dc->count));
|
||||
BUG_ON(refcount_read(&dc->count));
|
||||
|
||||
mutex_lock(&bch_register_lock);
|
||||
|
||||
|
|
@ -1016,7 +1029,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
|
|||
* dc->c must be set before dc->count != 0 - paired with the mb in
|
||||
* cached_dev_get()
|
||||
*/
|
||||
atomic_set(&dc->count, 1);
|
||||
refcount_set(&dc->count, 1);
|
||||
|
||||
/* Block writeback thread, but spawn it */
|
||||
down_write(&dc->writeback_lock);
|
||||
|
|
@ -1028,7 +1041,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
|
|||
if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
|
||||
bch_sectors_dirty_init(&dc->disk);
|
||||
atomic_set(&dc->has_dirty, 1);
|
||||
atomic_inc(&dc->count);
|
||||
refcount_inc(&dc->count);
|
||||
bch_writeback_queue(dc);
|
||||
}
|
||||
|
||||
|
|
@ -1129,9 +1142,6 @@ static int cached_dev_init(struct cached_dev *dc, unsigned block_size)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
set_capacity(dc->disk.disk,
|
||||
dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
|
||||
|
||||
dc->disk.disk->queue->backing_dev_info->ra_pages =
|
||||
max(dc->disk.disk->queue->backing_dev_info->ra_pages,
|
||||
q->backing_dev_info->ra_pages);
|
||||
|
|
@ -2085,6 +2095,7 @@ static void bcache_exit(void)
|
|||
if (bcache_major)
|
||||
unregister_blkdev(bcache_major, "bcache");
|
||||
unregister_reboot_notifier(&reboot);
|
||||
mutex_destroy(&bch_register_lock);
|
||||
}
|
||||
|
||||
static int __init bcache_init(void)
|
||||
|
|
@ -2103,14 +2114,15 @@ static int __init bcache_init(void)
|
|||
bcache_major = register_blkdev(0, "bcache");
|
||||
if (bcache_major < 0) {
|
||||
unregister_reboot_notifier(&reboot);
|
||||
mutex_destroy(&bch_register_lock);
|
||||
return bcache_major;
|
||||
}
|
||||
|
||||
if (!(bcache_wq = alloc_workqueue("bcache", WQ_MEM_RECLAIM, 0)) ||
|
||||
!(bcache_kobj = kobject_create_and_add("bcache", fs_kobj)) ||
|
||||
sysfs_create_files(bcache_kobj, files) ||
|
||||
bch_request_init() ||
|
||||
bch_debug_init(bcache_kobj))
|
||||
bch_debug_init(bcache_kobj) ||
|
||||
sysfs_create_files(bcache_kobj, files))
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -82,8 +82,9 @@ rw_attribute(writeback_delay);
|
|||
rw_attribute(writeback_rate);
|
||||
|
||||
rw_attribute(writeback_rate_update_seconds);
|
||||
rw_attribute(writeback_rate_d_term);
|
||||
rw_attribute(writeback_rate_i_term_inverse);
|
||||
rw_attribute(writeback_rate_p_term_inverse);
|
||||
rw_attribute(writeback_rate_minimum);
|
||||
read_attribute(writeback_rate_debug);
|
||||
|
||||
read_attribute(stripe_size);
|
||||
|
|
@ -131,15 +132,16 @@ SHOW(__bch_cached_dev)
|
|||
sysfs_hprint(writeback_rate, dc->writeback_rate.rate << 9);
|
||||
|
||||
var_print(writeback_rate_update_seconds);
|
||||
var_print(writeback_rate_d_term);
|
||||
var_print(writeback_rate_i_term_inverse);
|
||||
var_print(writeback_rate_p_term_inverse);
|
||||
var_print(writeback_rate_minimum);
|
||||
|
||||
if (attr == &sysfs_writeback_rate_debug) {
|
||||
char rate[20];
|
||||
char dirty[20];
|
||||
char target[20];
|
||||
char proportional[20];
|
||||
char derivative[20];
|
||||
char integral[20];
|
||||
char change[20];
|
||||
s64 next_io;
|
||||
|
||||
|
|
@ -147,7 +149,7 @@ SHOW(__bch_cached_dev)
|
|||
bch_hprint(dirty, bcache_dev_sectors_dirty(&dc->disk) << 9);
|
||||
bch_hprint(target, dc->writeback_rate_target << 9);
|
||||
bch_hprint(proportional,dc->writeback_rate_proportional << 9);
|
||||
bch_hprint(derivative, dc->writeback_rate_derivative << 9);
|
||||
bch_hprint(integral, dc->writeback_rate_integral_scaled << 9);
|
||||
bch_hprint(change, dc->writeback_rate_change << 9);
|
||||
|
||||
next_io = div64_s64(dc->writeback_rate.next - local_clock(),
|
||||
|
|
@ -158,11 +160,11 @@ SHOW(__bch_cached_dev)
|
|||
"dirty:\t\t%s\n"
|
||||
"target:\t\t%s\n"
|
||||
"proportional:\t%s\n"
|
||||
"derivative:\t%s\n"
|
||||
"integral:\t%s\n"
|
||||
"change:\t\t%s/sec\n"
|
||||
"next io:\t%llims\n",
|
||||
rate, dirty, target, proportional,
|
||||
derivative, change, next_io);
|
||||
integral, change, next_io);
|
||||
}
|
||||
|
||||
sysfs_hprint(dirty_data,
|
||||
|
|
@ -214,7 +216,7 @@ STORE(__cached_dev)
|
|||
dc->writeback_rate.rate, 1, INT_MAX);
|
||||
|
||||
d_strtoul_nonzero(writeback_rate_update_seconds);
|
||||
d_strtoul(writeback_rate_d_term);
|
||||
d_strtoul(writeback_rate_i_term_inverse);
|
||||
d_strtoul_nonzero(writeback_rate_p_term_inverse);
|
||||
|
||||
d_strtoi_h(sequential_cutoff);
|
||||
|
|
@ -320,7 +322,7 @@ static struct attribute *bch_cached_dev_files[] = {
|
|||
&sysfs_writeback_percent,
|
||||
&sysfs_writeback_rate,
|
||||
&sysfs_writeback_rate_update_seconds,
|
||||
&sysfs_writeback_rate_d_term,
|
||||
&sysfs_writeback_rate_i_term_inverse,
|
||||
&sysfs_writeback_rate_p_term_inverse,
|
||||
&sysfs_writeback_rate_debug,
|
||||
&sysfs_dirty_data,
|
||||
|
|
@ -746,6 +748,11 @@ static struct attribute *bch_cache_set_internal_files[] = {
|
|||
};
|
||||
KTYPE(bch_cache_set_internal);
|
||||
|
||||
static int __bch_cache_cmp(const void *l, const void *r)
|
||||
{
|
||||
return *((uint16_t *)r) - *((uint16_t *)l);
|
||||
}
|
||||
|
||||
SHOW(__bch_cache)
|
||||
{
|
||||
struct cache *ca = container_of(kobj, struct cache, kobj);
|
||||
|
|
@ -770,9 +777,6 @@ SHOW(__bch_cache)
|
|||
CACHE_REPLACEMENT(&ca->sb));
|
||||
|
||||
if (attr == &sysfs_priority_stats) {
|
||||
int cmp(const void *l, const void *r)
|
||||
{ return *((uint16_t *) r) - *((uint16_t *) l); }
|
||||
|
||||
struct bucket *b;
|
||||
size_t n = ca->sb.nbuckets, i;
|
||||
size_t unused = 0, available = 0, dirty = 0, meta = 0;
|
||||
|
|
@ -801,7 +805,7 @@ SHOW(__bch_cache)
|
|||
p[i] = ca->buckets[i].prio;
|
||||
mutex_unlock(&ca->set->bucket_lock);
|
||||
|
||||
sort(p, n, sizeof(uint16_t), cmp, NULL);
|
||||
sort(p, n, sizeof(uint16_t), __bch_cache_cmp, NULL);
|
||||
|
||||
while (n &&
|
||||
!cached[n - 1])
|
||||
|
|
|
|||
|
|
@ -232,8 +232,14 @@ uint64_t bch_next_delay(struct bch_ratelimit *d, uint64_t done)
|
|||
|
||||
d->next += div_u64(done * NSEC_PER_SEC, d->rate);
|
||||
|
||||
if (time_before64(now + NSEC_PER_SEC, d->next))
|
||||
d->next = now + NSEC_PER_SEC;
|
||||
/* Bound the time. Don't let us fall further than 2 seconds behind
|
||||
* (this prevents unnecessary backlog that would make it impossible
|
||||
* to catch up). If we're ahead of the desired writeback rate,
|
||||
* don't let us sleep more than 2.5 seconds (so we can notice/respond
|
||||
* if the control system tells us to speed up!).
|
||||
*/
|
||||
if (time_before64(now + NSEC_PER_SEC * 5LLU / 2LLU, d->next))
|
||||
d->next = now + NSEC_PER_SEC * 5LLU / 2LLU;
|
||||
|
||||
if (time_after64(now - NSEC_PER_SEC * 2, d->next))
|
||||
d->next = now - NSEC_PER_SEC * 2;
|
||||
|
|
|
|||
|
|
@ -442,10 +442,10 @@ struct bch_ratelimit {
|
|||
uint64_t next;
|
||||
|
||||
/*
|
||||
* Rate at which we want to do work, in units per nanosecond
|
||||
* Rate at which we want to do work, in units per second
|
||||
* The units here correspond to the units passed to bch_next_delay()
|
||||
*/
|
||||
unsigned rate;
|
||||
uint32_t rate;
|
||||
};
|
||||
|
||||
static inline void bch_ratelimit_reset(struct bch_ratelimit *d)
|
||||
|
|
|
|||
|
|
@ -26,48 +26,63 @@ static void __update_writeback_rate(struct cached_dev *dc)
|
|||
bcache_flash_devs_sectors_dirty(c);
|
||||
uint64_t cache_dirty_target =
|
||||
div_u64(cache_sectors * dc->writeback_percent, 100);
|
||||
|
||||
int64_t target = div64_u64(cache_dirty_target * bdev_sectors(dc->bdev),
|
||||
c->cached_dev_sectors);
|
||||
|
||||
/* PD controller */
|
||||
|
||||
/*
|
||||
* PI controller:
|
||||
* Figures out the amount that should be written per second.
|
||||
*
|
||||
* First, the error (number of sectors that are dirty beyond our
|
||||
* target) is calculated. The error is accumulated (numerically
|
||||
* integrated).
|
||||
*
|
||||
* Then, the proportional value and integral value are scaled
|
||||
* based on configured values. These are stored as inverses to
|
||||
* avoid fixed point math and to make configuration easy-- e.g.
|
||||
* the default value of 40 for writeback_rate_p_term_inverse
|
||||
* attempts to write at a rate that would retire all the dirty
|
||||
* blocks in 40 seconds.
|
||||
*
|
||||
* The writeback_rate_i_inverse value of 10000 means that 1/10000th
|
||||
* of the error is accumulated in the integral term per second.
|
||||
* This acts as a slow, long-term average that is not subject to
|
||||
* variations in usage like the p term.
|
||||
*/
|
||||
int64_t dirty = bcache_dev_sectors_dirty(&dc->disk);
|
||||
int64_t derivative = dirty - dc->disk.sectors_dirty_last;
|
||||
int64_t proportional = dirty - target;
|
||||
int64_t change;
|
||||
int64_t error = dirty - target;
|
||||
int64_t proportional_scaled =
|
||||
div_s64(error, dc->writeback_rate_p_term_inverse);
|
||||
int64_t integral_scaled;
|
||||
uint32_t new_rate;
|
||||
|
||||
dc->disk.sectors_dirty_last = dirty;
|
||||
if ((error < 0 && dc->writeback_rate_integral > 0) ||
|
||||
(error > 0 && time_before64(local_clock(),
|
||||
dc->writeback_rate.next + NSEC_PER_MSEC))) {
|
||||
/*
|
||||
* Only decrease the integral term if it's more than
|
||||
* zero. Only increase the integral term if the device
|
||||
* is keeping up. (Don't wind up the integral
|
||||
* ineffectively in either case).
|
||||
*
|
||||
* It's necessary to scale this by
|
||||
* writeback_rate_update_seconds to keep the integral
|
||||
* term dimensioned properly.
|
||||
*/
|
||||
dc->writeback_rate_integral += error *
|
||||
dc->writeback_rate_update_seconds;
|
||||
}
|
||||
|
||||
/* Scale to sectors per second */
|
||||
integral_scaled = div_s64(dc->writeback_rate_integral,
|
||||
dc->writeback_rate_i_term_inverse);
|
||||
|
||||
proportional *= dc->writeback_rate_update_seconds;
|
||||
proportional = div_s64(proportional, dc->writeback_rate_p_term_inverse);
|
||||
new_rate = clamp_t(int32_t, (proportional_scaled + integral_scaled),
|
||||
dc->writeback_rate_minimum, NSEC_PER_SEC);
|
||||
|
||||
derivative = div_s64(derivative, dc->writeback_rate_update_seconds);
|
||||
|
||||
derivative = ewma_add(dc->disk.sectors_dirty_derivative, derivative,
|
||||
(dc->writeback_rate_d_term /
|
||||
dc->writeback_rate_update_seconds) ?: 1, 0);
|
||||
|
||||
derivative *= dc->writeback_rate_d_term;
|
||||
derivative = div_s64(derivative, dc->writeback_rate_p_term_inverse);
|
||||
|
||||
change = proportional + derivative;
|
||||
|
||||
/* Don't increase writeback rate if the device isn't keeping up */
|
||||
if (change > 0 &&
|
||||
time_after64(local_clock(),
|
||||
dc->writeback_rate.next + NSEC_PER_MSEC))
|
||||
change = 0;
|
||||
|
||||
dc->writeback_rate.rate =
|
||||
clamp_t(int64_t, (int64_t) dc->writeback_rate.rate + change,
|
||||
1, NSEC_PER_MSEC);
|
||||
|
||||
dc->writeback_rate_proportional = proportional;
|
||||
dc->writeback_rate_derivative = derivative;
|
||||
dc->writeback_rate_change = change;
|
||||
dc->writeback_rate_proportional = proportional_scaled;
|
||||
dc->writeback_rate_integral_scaled = integral_scaled;
|
||||
dc->writeback_rate_change = new_rate - dc->writeback_rate.rate;
|
||||
dc->writeback_rate.rate = new_rate;
|
||||
dc->writeback_rate_target = target;
|
||||
}
|
||||
|
||||
|
|
@ -180,13 +195,21 @@ static void write_dirty(struct closure *cl)
|
|||
struct dirty_io *io = container_of(cl, struct dirty_io, cl);
|
||||
struct keybuf_key *w = io->bio.bi_private;
|
||||
|
||||
dirty_init(w);
|
||||
bio_set_op_attrs(&io->bio, REQ_OP_WRITE, 0);
|
||||
io->bio.bi_iter.bi_sector = KEY_START(&w->key);
|
||||
bio_set_dev(&io->bio, io->dc->bdev);
|
||||
io->bio.bi_end_io = dirty_endio;
|
||||
/*
|
||||
* IO errors are signalled using the dirty bit on the key.
|
||||
* If we failed to read, we should not attempt to write to the
|
||||
* backing device. Instead, immediately go to write_dirty_finish
|
||||
* to clean up.
|
||||
*/
|
||||
if (KEY_DIRTY(&w->key)) {
|
||||
dirty_init(w);
|
||||
bio_set_op_attrs(&io->bio, REQ_OP_WRITE, 0);
|
||||
io->bio.bi_iter.bi_sector = KEY_START(&w->key);
|
||||
bio_set_dev(&io->bio, io->dc->bdev);
|
||||
io->bio.bi_end_io = dirty_endio;
|
||||
|
||||
closure_bio_submit(&io->bio, cl);
|
||||
closure_bio_submit(&io->bio, cl);
|
||||
}
|
||||
|
||||
continue_at(cl, write_dirty_finish, io->dc->writeback_write_wq);
|
||||
}
|
||||
|
|
@ -418,6 +441,8 @@ static int bch_writeback_thread(void *arg)
|
|||
struct cached_dev *dc = arg;
|
||||
bool searched_full_index;
|
||||
|
||||
bch_ratelimit_reset(&dc->writeback_rate);
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
down_write(&dc->writeback_lock);
|
||||
if (!atomic_read(&dc->has_dirty) ||
|
||||
|
|
@ -445,7 +470,6 @@ static int bch_writeback_thread(void *arg)
|
|||
|
||||
up_write(&dc->writeback_lock);
|
||||
|
||||
bch_ratelimit_reset(&dc->writeback_rate);
|
||||
read_dirty(dc);
|
||||
|
||||
if (searched_full_index) {
|
||||
|
|
@ -455,6 +479,8 @@ static int bch_writeback_thread(void *arg)
|
|||
!kthread_should_stop() &&
|
||||
!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags))
|
||||
delay = schedule_timeout_interruptible(delay);
|
||||
|
||||
bch_ratelimit_reset(&dc->writeback_rate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -492,8 +518,6 @@ void bch_sectors_dirty_init(struct bcache_device *d)
|
|||
|
||||
bch_btree_map_keys(&op.op, d->c, &KEY(op.inode, 0, 0),
|
||||
sectors_dirty_init_fn, 0);
|
||||
|
||||
d->sectors_dirty_last = bcache_dev_sectors_dirty(d);
|
||||
}
|
||||
|
||||
void bch_cached_dev_writeback_init(struct cached_dev *dc)
|
||||
|
|
@ -507,10 +531,11 @@ void bch_cached_dev_writeback_init(struct cached_dev *dc)
|
|||
dc->writeback_percent = 10;
|
||||
dc->writeback_delay = 30;
|
||||
dc->writeback_rate.rate = 1024;
|
||||
dc->writeback_rate_minimum = 8;
|
||||
|
||||
dc->writeback_rate_update_seconds = 5;
|
||||
dc->writeback_rate_d_term = 30;
|
||||
dc->writeback_rate_p_term_inverse = 6000;
|
||||
dc->writeback_rate_p_term_inverse = 40;
|
||||
dc->writeback_rate_i_term_inverse = 10000;
|
||||
|
||||
INIT_DELAYED_WORK(&dc->writeback_rate_update, update_writeback_rate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,9 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio,
|
|||
if (would_skip)
|
||||
return false;
|
||||
|
||||
return op_is_sync(bio->bi_opf) || in_use <= CUTOFF_WRITEBACK;
|
||||
return (op_is_sync(bio->bi_opf) ||
|
||||
bio->bi_opf & (REQ_META|REQ_PRIO) ||
|
||||
in_use <= CUTOFF_WRITEBACK);
|
||||
}
|
||||
|
||||
static inline void bch_writeback_queue(struct cached_dev *dc)
|
||||
|
|
@ -90,7 +92,7 @@ static inline void bch_writeback_add(struct cached_dev *dc)
|
|||
{
|
||||
if (!atomic_read(&dc->has_dirty) &&
|
||||
!atomic_xchg(&dc->has_dirty, 1)) {
|
||||
atomic_inc(&dc->count);
|
||||
refcount_inc(&dc->count);
|
||||
|
||||
if (BDEV_STATE(&dc->sb) != BDEV_STATE_DIRTY) {
|
||||
SET_BDEV_STATE(&dc->sb, BDEV_STATE_DIRTY);
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ static int read_page(struct file *file, unsigned long index,
|
|||
pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE,
|
||||
(unsigned long long)index << PAGE_SHIFT);
|
||||
|
||||
bh = alloc_page_buffers(page, 1<<inode->i_blkbits, 0);
|
||||
bh = alloc_page_buffers(page, 1<<inode->i_blkbits, false);
|
||||
if (!bh) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ static unsigned dm_get_blk_mq_queue_depth(void)
|
|||
|
||||
int dm_request_based(struct mapped_device *md)
|
||||
{
|
||||
return blk_queue_stackable(md->queue);
|
||||
return queue_is_rq_based(md->queue);
|
||||
}
|
||||
|
||||
static void dm_old_start_queue(struct request_queue *q)
|
||||
|
|
|
|||
|
|
@ -1000,7 +1000,7 @@ verify_rq_based:
|
|||
list_for_each_entry(dd, devices, list) {
|
||||
struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev);
|
||||
|
||||
if (!blk_queue_stackable(q)) {
|
||||
if (!queue_is_rq_based(q)) {
|
||||
DMERR("table load rejected: including"
|
||||
" non-request-stackable devices");
|
||||
return -EINVAL;
|
||||
|
|
@ -1847,19 +1847,6 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
|
|||
*/
|
||||
if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random))
|
||||
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, q);
|
||||
|
||||
/*
|
||||
* QUEUE_FLAG_STACKABLE must be set after all queue settings are
|
||||
* visible to other CPUs because, once the flag is set, incoming bios
|
||||
* are processed by request-based dm, which refers to the queue
|
||||
* settings.
|
||||
* Until the flag set, bios are passed to bio-based dm and queued to
|
||||
* md->deferred where queue settings are not needed yet.
|
||||
* Those bios are passed to request-based dm at the resume time.
|
||||
*/
|
||||
smp_mb();
|
||||
if (dm_table_request_based(t))
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_STACKABLE, q);
|
||||
}
|
||||
|
||||
unsigned int dm_table_get_num_targets(struct dm_table *t)
|
||||
|
|
|
|||
|
|
@ -1618,17 +1618,6 @@ static void dm_wq_work(struct work_struct *work);
|
|||
|
||||
void dm_init_md_queue(struct mapped_device *md)
|
||||
{
|
||||
/*
|
||||
* Request-based dm devices cannot be stacked on top of bio-based dm
|
||||
* devices. The type of this dm device may not have been decided yet.
|
||||
* The type is decided at the first table loading time.
|
||||
* To prevent problematic device stacking, clear the queue flag
|
||||
* for request stacking support until then.
|
||||
*
|
||||
* This queue is new, so no concurrency on the queue_flags.
|
||||
*/
|
||||
queue_flag_clear_unlocked(QUEUE_FLAG_STACKABLE, md->queue);
|
||||
|
||||
/*
|
||||
* Initialize data that will only be used by a non-blk-mq DM queue
|
||||
* - must do so here (in alloc_dev callchain) before queue is used
|
||||
|
|
|
|||
Loading…
Reference in a new issue