Skip to content

Commit 279afba

Browse files
author
Kent Overstreet
committed
bcache: Track dirty data by stripe
To make background writeback aware of raid5/6 stripes, we first need to track the amount of dirty data within each stripe - we do this by breaking up the existing sectors_dirty into per stripe atomic_ts Signed-off-by: Kent Overstreet <[email protected]>
1 parent 444fc0b commit 279afba

File tree

7 files changed

+105
-26
lines changed

7 files changed

+105
-26
lines changed

drivers/md/bcache/bcache.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,10 @@ struct bcache_device {
437437
/* If nonzero, we're detaching/unregistering from cache set */
438438
atomic_t detaching;
439439

440-
atomic_long_t sectors_dirty;
440+
uint64_t nr_stripes;
441+
unsigned stripe_size_bits;
442+
atomic_t *stripe_sectors_dirty;
443+
441444
unsigned long sectors_dirty_last;
442445
long sectors_dirty_derivative;
443446

@@ -1159,9 +1162,6 @@ static inline void wake_up_allocators(struct cache_set *c)
11591162

11601163
/* Forward declarations */
11611164

1162-
void bch_writeback_queue(struct cached_dev *);
1163-
void bch_writeback_add(struct cached_dev *, unsigned);
1164-
11651165
void bch_count_io_errors(struct cache *, int, const char *);
11661166
void bch_bbio_count_io_errors(struct cache_set *, struct bio *,
11671167
int, const char *);
@@ -1224,8 +1224,6 @@ void bch_cache_set_stop(struct cache_set *);
12241224
struct cache_set *bch_cache_set_alloc(struct cache_sb *);
12251225
void bch_btree_cache_free(struct cache_set *);
12261226
int bch_btree_cache_alloc(struct cache_set *);
1227-
void bch_sectors_dirty_init(struct cached_dev *);
1228-
void bch_cached_dev_writeback_init(struct cached_dev *);
12291227
void bch_moving_init_cache_set(struct cache_set *);
12301228

12311229
int bch_cache_allocator_start(struct cache *ca);

drivers/md/bcache/btree.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "btree.h"
2525
#include "debug.h"
2626
#include "request.h"
27+
#include "writeback.h"
2728

2829
#include <linux/slab.h>
2930
#include <linux/bitops.h>
@@ -1599,14 +1600,14 @@ static bool fix_overlapping_extents(struct btree *b,
15991600
struct btree_iter *iter,
16001601
struct btree_op *op)
16011602
{
1602-
void subtract_dirty(struct bkey *k, int sectors)
1603+
void subtract_dirty(struct bkey *k, uint64_t offset, int sectors)
16031604
{
1604-
struct bcache_device *d = b->c->devices[KEY_INODE(k)];
1605-
1606-
if (KEY_DIRTY(k) && d)
1607-
atomic_long_sub(sectors, &d->sectors_dirty);
1605+
if (KEY_DIRTY(k))
1606+
bcache_dev_sectors_dirty_add(b->c, KEY_INODE(k),
1607+
offset, -sectors);
16081608
}
16091609

1610+
uint64_t old_offset;
16101611
unsigned old_size, sectors_found = 0;
16111612

16121613
while (1) {
@@ -1618,6 +1619,7 @@ static bool fix_overlapping_extents(struct btree *b,
16181619
if (bkey_cmp(k, &START_KEY(insert)) <= 0)
16191620
continue;
16201621

1622+
old_offset = KEY_START(k);
16211623
old_size = KEY_SIZE(k);
16221624

16231625
/*
@@ -1673,7 +1675,7 @@ static bool fix_overlapping_extents(struct btree *b,
16731675

16741676
struct bkey *top;
16751677

1676-
subtract_dirty(k, KEY_SIZE(insert));
1678+
subtract_dirty(k, KEY_START(insert), KEY_SIZE(insert));
16771679

16781680
if (bkey_written(b, k)) {
16791681
/*
@@ -1720,7 +1722,7 @@ static bool fix_overlapping_extents(struct btree *b,
17201722
}
17211723
}
17221724

1723-
subtract_dirty(k, old_size - KEY_SIZE(k));
1725+
subtract_dirty(k, old_offset, old_size - KEY_SIZE(k));
17241726
}
17251727

17261728
check_failed:
@@ -1796,6 +1798,10 @@ static bool btree_insert_key(struct btree *b, struct btree_op *op,
17961798
insert: shift_keys(b, m, k);
17971799
copy: bkey_copy(m, k);
17981800
merged:
1801+
if (KEY_DIRTY(k))
1802+
bcache_dev_sectors_dirty_add(b->c, KEY_INODE(k),
1803+
KEY_START(k), KEY_SIZE(k));
1804+
17991805
bch_check_keys(b, "%u for %s", status, op_type(op));
18001806

18011807
if (b->level && !KEY_OFFSET(k))

drivers/md/bcache/request.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "btree.h"
1111
#include "debug.h"
1212
#include "request.h"
13+
#include "writeback.h"
1314

1415
#include <linux/cgroup.h>
1516
#include <linux/module.h>
@@ -1044,7 +1045,7 @@ static void request_write(struct cached_dev *dc, struct search *s)
10441045
closure_bio_submit(bio, cl, s->d);
10451046
} else {
10461047
s->op.cache_bio = bio;
1047-
bch_writeback_add(dc, bio_sectors(bio));
1048+
bch_writeback_add(dc);
10481049
}
10491050
out:
10501051
closure_call(&s->op.cl, bch_insert_data, NULL, cl);

drivers/md/bcache/super.c

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "btree.h"
1111
#include "debug.h"
1212
#include "request.h"
13+
#include "writeback.h"
1314

1415
#include <linux/blkdev.h>
1516
#include <linux/buffer_head.h>
@@ -744,13 +745,35 @@ static void bcache_device_free(struct bcache_device *d)
744745
mempool_destroy(d->unaligned_bvec);
745746
if (d->bio_split)
746747
bioset_free(d->bio_split);
748+
if (is_vmalloc_addr(d->stripe_sectors_dirty))
749+
vfree(d->stripe_sectors_dirty);
750+
else
751+
kfree(d->stripe_sectors_dirty);
747752

748753
closure_debug_destroy(&d->cl);
749754
}
750755

751-
static int bcache_device_init(struct bcache_device *d, unsigned block_size)
756+
static int bcache_device_init(struct bcache_device *d, unsigned block_size,
757+
sector_t sectors)
752758
{
753759
struct request_queue *q;
760+
size_t n;
761+
762+
if (!d->stripe_size_bits)
763+
d->stripe_size_bits = 31;
764+
765+
d->nr_stripes = round_up(sectors, 1 << d->stripe_size_bits) >>
766+
d->stripe_size_bits;
767+
768+
if (!d->nr_stripes || d->nr_stripes > SIZE_MAX / sizeof(atomic_t))
769+
return -ENOMEM;
770+
771+
n = d->nr_stripes * sizeof(atomic_t);
772+
d->stripe_sectors_dirty = n < PAGE_SIZE << 6
773+
? kzalloc(n, GFP_KERNEL)
774+
: vzalloc(n);
775+
if (!d->stripe_sectors_dirty)
776+
return -ENOMEM;
754777

755778
if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
756779
!(d->unaligned_bvec = mempool_create_kmalloc_pool(1,
@@ -760,6 +783,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size)
760783
!(q = blk_alloc_queue(GFP_KERNEL)))
761784
return -ENOMEM;
762785

786+
set_capacity(d->disk, sectors);
763787
snprintf(d->disk->disk_name, DISK_NAME_LEN, "bcache%i", bcache_minor);
764788

765789
d->disk->major = bcache_major;
@@ -1047,7 +1071,8 @@ static int cached_dev_init(struct cached_dev *dc, unsigned block_size)
10471071
hlist_add_head(&io->hash, dc->io_hash + RECENT_IO);
10481072
}
10491073

1050-
ret = bcache_device_init(&dc->disk, block_size);
1074+
ret = bcache_device_init(&dc->disk, block_size,
1075+
dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
10511076
if (ret)
10521077
return ret;
10531078

@@ -1146,11 +1171,10 @@ static int flash_dev_run(struct cache_set *c, struct uuid_entry *u)
11461171

11471172
kobject_init(&d->kobj, &bch_flash_dev_ktype);
11481173

1149-
if (bcache_device_init(d, block_bytes(c)))
1174+
if (bcache_device_init(d, block_bytes(c), u->sectors))
11501175
goto err;
11511176

11521177
bcache_device_attach(d, c, u - c->uuids);
1153-
set_capacity(d->disk, u->sectors);
11541178
bch_flash_dev_request_init(d);
11551179
add_disk(d->disk);
11561180

drivers/md/bcache/sysfs.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "sysfs.h"
1010
#include "btree.h"
1111
#include "request.h"
12+
#include "writeback.h"
1213

1314
#include <linux/blkdev.h>
1415
#include <linux/sort.h>
@@ -128,7 +129,7 @@ SHOW(__bch_cached_dev)
128129
char derivative[20];
129130
char target[20];
130131
bch_hprint(dirty,
131-
atomic_long_read(&dc->disk.sectors_dirty) << 9);
132+
bcache_dev_sectors_dirty(&dc->disk) << 9);
132133
bch_hprint(derivative, dc->writeback_rate_derivative << 9);
133134
bch_hprint(target, dc->writeback_rate_target << 9);
134135

@@ -144,7 +145,7 @@ SHOW(__bch_cached_dev)
144145
}
145146

146147
sysfs_hprint(dirty_data,
147-
atomic_long_read(&dc->disk.sectors_dirty) << 9);
148+
bcache_dev_sectors_dirty(&dc->disk) << 9);
148149

149150
var_printf(sequential_merge, "%i");
150151
var_hprint(sequential_cutoff);

drivers/md/bcache/writeback.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "bcache.h"
1010
#include "btree.h"
1111
#include "debug.h"
12+
#include "writeback.h"
1213

1314
#include <trace/events/bcache.h>
1415

@@ -38,7 +39,7 @@ static void __update_writeback_rate(struct cached_dev *dc)
3839

3940
int change = 0;
4041
int64_t error;
41-
int64_t dirty = atomic_long_read(&dc->disk.sectors_dirty);
42+
int64_t dirty = bcache_dev_sectors_dirty(&dc->disk);
4243
int64_t derivative = dirty - dc->disk.sectors_dirty_last;
4344

4445
dc->disk.sectors_dirty_last = dirty;
@@ -183,10 +184,8 @@ void bch_writeback_queue(struct cached_dev *dc)
183184
}
184185
}
185186

186-
void bch_writeback_add(struct cached_dev *dc, unsigned sectors)
187+
void bch_writeback_add(struct cached_dev *dc)
187188
{
188-
atomic_long_add(sectors, &dc->disk.sectors_dirty);
189-
190189
if (!atomic_read(&dc->has_dirty) &&
191190
!atomic_xchg(&dc->has_dirty, 1)) {
192191
atomic_inc(&dc->count);
@@ -205,6 +204,34 @@ void bch_writeback_add(struct cached_dev *dc, unsigned sectors)
205204
}
206205
}
207206

207+
void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode,
208+
uint64_t offset, int nr_sectors)
209+
{
210+
struct bcache_device *d = c->devices[inode];
211+
unsigned stripe_size, stripe_offset;
212+
uint64_t stripe;
213+
214+
if (!d)
215+
return;
216+
217+
stripe_size = 1 << d->stripe_size_bits;
218+
stripe = offset >> d->stripe_size_bits;
219+
stripe_offset = offset & (stripe_size - 1);
220+
221+
while (nr_sectors) {
222+
int s = min_t(unsigned, abs(nr_sectors),
223+
stripe_size - stripe_offset);
224+
225+
if (nr_sectors < 0)
226+
s = -s;
227+
228+
atomic_add(s, d->stripe_sectors_dirty + stripe);
229+
nr_sectors -= s;
230+
stripe_offset = 0;
231+
stripe++;
232+
}
233+
}
234+
208235
/* Background writeback - IO loop */
209236

210237
static void dirty_io_destructor(struct closure *cl)
@@ -392,8 +419,9 @@ static int bch_btree_sectors_dirty_init(struct btree *b, struct btree_op *op,
392419
break;
393420

394421
if (KEY_DIRTY(k))
395-
atomic_long_add(KEY_SIZE(k),
396-
&dc->disk.sectors_dirty);
422+
bcache_dev_sectors_dirty_add(b->c, dc->disk.id,
423+
KEY_START(k),
424+
KEY_SIZE(k));
397425
} else {
398426
btree(sectors_dirty_init, k, b, op, dc);
399427
if (KEY_INODE(k) > dc->disk.id)

drivers/md/bcache/writeback.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef _BCACHE_WRITEBACK_H
2+
#define _BCACHE_WRITEBACK_H
3+
4+
static inline uint64_t bcache_dev_sectors_dirty(struct bcache_device *d)
5+
{
6+
uint64_t i, ret = 0;
7+
8+
for (i = 0; i < d->nr_stripes; i++)
9+
ret += atomic_read(d->stripe_sectors_dirty + i);
10+
11+
return ret;
12+
}
13+
14+
void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int);
15+
void bch_writeback_queue(struct cached_dev *);
16+
void bch_writeback_add(struct cached_dev *);
17+
18+
void bch_sectors_dirty_init(struct cached_dev *dc);
19+
void bch_cached_dev_writeback_init(struct cached_dev *);
20+
21+
#endif

0 commit comments

Comments
 (0)