summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/dm-bufio.c9
-rw-r--r--drivers/md/dm-cache-metadata.c6
-rw-r--r--drivers/md/dm-cache-policy-internal.h3
-rw-r--r--drivers/md/dm-cache-policy-smq.c2
-rw-r--r--drivers/md/dm-cache-target.c12
-rw-r--r--drivers/md/dm-crypt.c3
-rw-r--r--drivers/md/dm-era-target.c10
-rw-r--r--drivers/md/dm-flakey.c1
-rw-r--r--drivers/md/dm-integrity.c79
-rw-r--r--drivers/md/dm-io.c1
-rw-r--r--drivers/md/dm-ioctl.c18
-rw-r--r--drivers/md/dm-kcopyd.c2
-rw-r--r--drivers/md/dm-log.c6
-rw-r--r--drivers/md/dm-mpath.c3
-rw-r--r--drivers/md/dm-rq.c2
-rw-r--r--drivers/md/dm-snap-persistent.c3
-rw-r--r--drivers/md/dm-snap.c7
-rw-r--r--drivers/md/dm-stats.c13
-rw-r--r--drivers/md/dm-sysfs.c1
-rw-r--r--drivers/md/dm-thin-metadata.c1
-rw-r--r--drivers/md/dm-thin.c5
-rw-r--r--drivers/md/dm-verity-target.c4
-rw-r--r--drivers/md/dm-writecache.c35
-rw-r--r--drivers/md/persistent-data/dm-array.c4
-rw-r--r--drivers/md/persistent-data/dm-bitset.c1
-rw-r--r--drivers/md/persistent-data/dm-block-manager.c7
-rw-r--r--drivers/md/persistent-data/dm-btree-internal.h1
-rw-r--r--drivers/md/persistent-data/dm-btree-remove.c5
-rw-r--r--drivers/md/persistent-data/dm-btree.c10
-rw-r--r--drivers/md/persistent-data/dm-space-map-common.c6
-rw-r--r--drivers/md/persistent-data/dm-space-map-disk.c3
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.c3
-rw-r--r--drivers/md/persistent-data/dm-transaction-manager.c1
33 files changed, 240 insertions, 27 deletions
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index b3dee6d61916..46b2cec9610a 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -628,6 +628,7 @@ static void bio_complete(struct bio *bio)
{
struct dm_buffer *b = bio->bi_private;
blk_status_t status = bio->bi_status;
+
bio_uninit(bio);
kfree(bio);
b->end_io(b, status);
@@ -660,6 +661,7 @@ dmio:
do {
unsigned int this_step = min((unsigned int)(PAGE_SIZE - offset_in_page(ptr)), len);
+
if (!bio_add_page(bio, virt_to_page(ptr), this_step,
offset_in_page(ptr))) {
bio_put(bio);
@@ -782,6 +784,7 @@ static void __write_dirty_buffer(struct dm_buffer *b,
static void __flush_write_list(struct list_head *write_list)
{
struct blk_plug plug;
+
blk_start_plug(&plug);
while (!list_empty(write_list)) {
struct dm_buffer *b =
@@ -1179,6 +1182,7 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
for (; n_blocks--; block++) {
int need_submit;
struct dm_buffer *b;
+
b = __bufio_new(c, block, NF_PREFETCH, &need_submit,
&write_list);
if (unlikely(!list_empty(&write_list))) {
@@ -1463,6 +1467,7 @@ retry:
__link_buffer(b, new_block, LIST_DIRTY);
} else {
sector_t old_block;
+
wait_on_bit_lock_io(&b->state, B_WRITING,
TASK_UNINTERRUPTIBLE);
/*
@@ -1553,6 +1558,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_get_block_size);
sector_t dm_bufio_get_device_size(struct dm_bufio_client *c)
{
sector_t s = bdev_nr_sectors(c->bdev);
+
if (s >= c->start)
s -= c->start;
else
@@ -1668,10 +1674,12 @@ static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp)
static unsigned long get_retain_buffers(struct dm_bufio_client *c)
{
unsigned long retain_bytes = READ_ONCE(dm_bufio_retain_bytes);
+
if (likely(c->sectors_per_block_bits >= 0))
retain_bytes >>= c->sectors_per_block_bits + SECTOR_SHIFT;
else
retain_bytes /= c->block_size;
+
return retain_bytes;
}
@@ -1806,6 +1814,7 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
if (block_size <= KMALLOC_MAX_SIZE &&
(block_size < PAGE_SIZE || !is_power_of_2(block_size))) {
unsigned int align = min(1U << __ffs(block_size), (unsigned int)PAGE_SIZE);
+
snprintf(slab_name, sizeof slab_name, "dm_bufio_cache-%u", block_size);
c->slab_cache = kmem_cache_create(slab_name, block_size, align,
SLAB_RECLAIM_ACCOUNT, NULL);
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index 692d292f876f..9249c75dd0bb 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -535,6 +535,7 @@ static int __create_persistent_data_objects(struct dm_cache_metadata *cmd,
bool may_format_device)
{
int r;
+
cmd->bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
CACHE_MAX_CONCURRENT_LOCKS);
if (IS_ERR(cmd->bm)) {
@@ -568,6 +569,7 @@ static void update_flags(struct cache_disk_superblock *disk_super,
flags_mutator mutator)
{
uint32_t sb_flags = mutator(le32_to_cpu(disk_super->flags));
+
disk_super->flags = cpu_to_le32(sb_flags);
}
@@ -732,6 +734,7 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
static __le64 pack_value(dm_oblock_t block, unsigned int flags)
{
uint64_t value = from_oblock(block);
+
value <<= 16;
value = value | (flags & FLAGS_MASK);
return cpu_to_le64(value);
@@ -741,6 +744,7 @@ static void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned int *flag
{
uint64_t value = le64_to_cpu(value_le);
uint64_t b = value >> 16;
+
*block = to_oblock(b);
*flags = value & FLAGS_MASK;
}
@@ -1254,6 +1258,7 @@ static int __insert(struct dm_cache_metadata *cmd,
{
int r;
__le64 value = pack_value(oblock, M_VALID);
+
__dm_bless_for_disk(&value);
r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock),
@@ -1580,6 +1585,7 @@ static int __set_dirty_bits_v1(struct dm_cache_metadata *cmd, unsigned int nr_bi
{
int r;
unsigned int i;
+
for (i = 0; i < nr_bits; i++) {
r = __dirty(cmd, to_cblock(i), test_bit(i, bits));
if (r)
diff --git a/drivers/md/dm-cache-policy-internal.h b/drivers/md/dm-cache-policy-internal.h
index aa73fd0976ec..476a4f6794fc 100644
--- a/drivers/md/dm-cache-policy-internal.h
+++ b/drivers/md/dm-cache-policy-internal.h
@@ -89,6 +89,7 @@ static inline int policy_emit_config_values(struct dm_cache_policy *p, char *res
unsigned int maxlen, ssize_t *sz_ptr)
{
ssize_t sz = *sz_ptr;
+
if (p->emit_config_values)
return p->emit_config_values(p, result, maxlen, sz_ptr);
@@ -121,12 +122,14 @@ static inline size_t bitset_size_in_bytes(unsigned int nr_entries)
static inline unsigned long *alloc_bitset(unsigned int nr_entries)
{
size_t s = bitset_size_in_bytes(nr_entries);
+
return vzalloc(s);
}
static inline void clear_bitset(void *bitset, unsigned int nr_entries)
{
size_t s = bitset_size_in_bytes(nr_entries);
+
memset(bitset, 0, s);
}
diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c
index cd3a37ffb33e..493a8715dc8f 100644
--- a/drivers/md/dm-cache-policy-smq.c
+++ b/drivers/md/dm-cache-policy-smq.c
@@ -624,6 +624,7 @@ static void __h_insert(struct smq_hash_table *ht, unsigned int bucket, struct en
static void h_insert(struct smq_hash_table *ht, struct entry *e)
{
unsigned int h = hash_64(from_oblock(e->oblock), ht->hash_bits);
+
__h_insert(ht, h, e);
}
@@ -1633,6 +1634,7 @@ static void smq_tick(struct dm_cache_policy *p, bool can_block)
static void smq_allow_migrations(struct dm_cache_policy *p, bool allow)
{
struct smq_policy *mq = to_smq_policy(p);
+
mq->migrations_allowed = allow;
}
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 60f7f1e45a8f..8de5e4df0661 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -534,6 +534,7 @@ static unsigned int lock_level(struct bio *bio)
static struct per_bio_data *get_per_bio_data(struct bio *bio)
{
struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
+
BUG_ON(!pb);
return pb;
}
@@ -690,6 +691,7 @@ static void clear_discard(struct cache *cache, dm_dblock_t b)
static bool is_discarded(struct cache *cache, dm_dblock_t b)
{
int r;
+
spin_lock_irq(&cache->lock);
r = test_bit(from_dblock(b), cache->discard_bitset);
spin_unlock_irq(&cache->lock);
@@ -700,6 +702,7 @@ static bool is_discarded(struct cache *cache, dm_dblock_t b)
static bool is_discarded_oblock(struct cache *cache, dm_oblock_t b)
{
int r;
+
spin_lock_irq(&cache->lock);
r = test_bit(from_dblock(oblock_to_dblock(cache, b)),
cache->discard_bitset);
@@ -814,6 +817,7 @@ static void accounted_request(struct cache *cache, struct bio *bio)
static void issue_op(struct bio *bio, void *context)
{
struct cache *cache = context;
+
accounted_request(cache, bio);
}
@@ -1074,6 +1078,7 @@ static void quiesce(struct dm_cache_migration *mg,
static struct dm_cache_migration *ws_to_mg(struct work_struct *ws)
{
struct continuation *k = container_of(ws, struct continuation, ws);
+
return container_of(k, struct dm_cache_migration, k);
}
@@ -1225,6 +1230,7 @@ static void mg_complete(struct dm_cache_migration *mg, bool success)
static void mg_success(struct work_struct *ws)
{
struct dm_cache_migration *mg = ws_to_mg(ws);
+
mg_complete(mg, mg->k.input == 0);
}
@@ -1363,6 +1369,7 @@ static void mg_copy(struct work_struct *ws)
* Fallback to a real full copy after doing some tidying up.
*/
bool rb = bio_detain_shared(mg->cache, mg->op->oblock, mg->overwrite_bio);
+
BUG_ON(rb); /* An exclussive lock must _not_ be held for this block */
mg->overwrite_bio = NULL;
inc_io_migrations(mg->cache);
@@ -1465,12 +1472,15 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success)
static void invalidate_completed(struct work_struct *ws)
{
struct dm_cache_migration *mg = ws_to_mg(ws);
+
invalidate_complete(mg, !mg->k.input);
}
static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock)
{
- int r = policy_invalidate_mapping(cache->policy, cblock);
+ int r;
+
+ r = policy_invalidate_mapping(cache->policy, cblock);
if (!r) {
r = dm_cache_remove_mapping(cache->cmd, cblock);
if (r) {
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 839baff49912..f186c450136c 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1257,6 +1257,7 @@ static __le64 *org_sector_of_dmreq(struct crypt_config *cc,
struct dm_crypt_request *dmreq)
{
u8 *ptr = iv_of_dmreq(cc, dmreq) + cc->iv_size + cc->iv_size;
+
return (__le64 *) ptr;
}
@@ -1265,6 +1266,7 @@ static unsigned int *org_tag_of_dmreq(struct crypt_config *cc,
{
u8 *ptr = iv_of_dmreq(cc, dmreq) + cc->iv_size +
cc->iv_size + sizeof(uint64_t);
+
return (unsigned int *)ptr;
}
@@ -1741,6 +1743,7 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
static void kcryptd_io_bio_endio(struct work_struct *work)
{
struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
+
bio_endio(io->base_bio);
}
diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c
index a42cfd950e04..f8f7994f4f27 100644
--- a/drivers/md/dm-era-target.c
+++ b/drivers/md/dm-era-target.c
@@ -112,13 +112,14 @@ static int writeset_marked_on_disk(struct dm_disk_bitset *info,
struct writeset_metadata *m, dm_block_t block,
bool *result)
{
+ int r;
dm_block_t old = m->root;
/*
* The bitset was flushed when it was archived, so we know there'll
* be no change to the root.
*/
- int r = dm_bitset_test_bit(info, m->root, block, &m->root, result);
+ r = dm_bitset_test_bit(info, m->root, block, &m->root, result);
if (r) {
DMERR("%s: dm_bitset_test_bit failed", __func__);
return r;
@@ -210,6 +211,7 @@ static void sb_prepare_for_write(struct dm_block_validator *v,
static int check_metadata_version(struct superblock_disk *disk)
{
uint32_t metadata_version = le32_to_cpu(disk->version);
+
if (metadata_version < MIN_ERA_VERSION || metadata_version > MAX_ERA_VERSION) {
DMERR("Era metadata version %u found, but only versions between %u and %u supported.",
metadata_version, MIN_ERA_VERSION, MAX_ERA_VERSION);
@@ -409,6 +411,7 @@ static int ws_eq(void *context, const void *value1, const void *value2)
static void setup_writeset_tree_info(struct era_metadata *md)
{
struct dm_btree_value_type *vt = &md->writeset_tree_info.value_type;
+
md->writeset_tree_info.tm = md->tm;
md->writeset_tree_info.levels = 1;
vt->context = md;
@@ -419,9 +422,9 @@ static void setup_writeset_tree_info(struct era_metadata *md)
}
static void setup_era_array_info(struct era_metadata *md)
-
{
struct dm_btree_value_type vt;
+
vt.context = NULL;
vt.size = sizeof(__le32);
vt.inc = NULL;
@@ -1391,6 +1394,7 @@ static int perform_rpc(struct era *era, struct rpc *rpc)
static int in_worker0(struct era *era, int (*fn)(struct era_metadata *md))
{
struct rpc rpc;
+
rpc.fn0 = fn;
rpc.fn1 = NULL;
@@ -1401,6 +1405,7 @@ static int in_worker1(struct era *era,
int (*fn)(struct era_metadata *md, void *ref), void *arg)
{
struct rpc rpc;
+
rpc.fn0 = NULL;
rpc.fn1 = fn;
rpc.arg = arg;
@@ -1712,6 +1717,7 @@ static int era_iterate_devices(struct dm_target *ti,
iterate_devices_callout_fn fn, void *data)
{
struct era *era = ti->private;
+
return fn(ti, era->origin_dev, 0, get_dev_size(era->origin_dev), data);
}
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index 51116e9008e5..5b7556d2a9d9 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -327,6 +327,7 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
struct flakey_c *fc = ti->private;
unsigned int elapsed;
struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
+
pb->bio_submitted = false;
if (op_is_zone_mgmt(bio_op(bio)))
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 524fecad0563..3cbefa8da51e 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -346,6 +346,7 @@ static struct kmem_cache *journal_io_cache;
static void __DEBUG_bytes(__u8 *bytes, size_t len, const char *msg, ...)
{
va_list args;
+
va_start(args, msg);
vprintk(msg, args);
va_end(args);
@@ -538,6 +539,7 @@ static int sb_mac(struct dm_integrity_c *ic, bool wr)
}
} else {
__u8 result[HASH_MAX_DIGESTSIZE];
+
r = crypto_shash_final(desc, result);
if (unlikely(r < 0)) {
dm_integrity_io_error(ic, "crypto_shash_final", r);
@@ -713,6 +715,7 @@ static void block_bitmap_copy(struct dm_integrity_c *ic, struct page_list *dst,
for (i = 0; i < n_bitmap_pages; i++) {
unsigned long *dst_data = lowmem_page_address(dst[i].page);
unsigned long *src_data = lowmem_page_address(src[i].page);
+
copy_page(dst_data, src_data);
}
}
@@ -833,6 +836,7 @@ static void section_mac(struct dm_integrity_c *ic, unsigned int section, __u8 re
for (j = 0; j < ic->journal_section_entries; j++) {
struct journal_entry *je = access_journal_entry(ic, section, j);
+
r = crypto_shash_update(desc, (__u8 *)&je->u.sector, sizeof je->u.sector);
if (unlikely(r < 0)) {
dm_integrity_io_error(ic, "crypto_shash_update", r);
@@ -896,6 +900,7 @@ static void rw_section_mac(struct dm_integrity_c *ic, unsigned int section, bool
static void complete_journal_op(void *context)
{
struct journal_completion *comp = context;
+
BUG_ON(!atomic_read(&comp->in_flight));
if (likely(atomic_dec_and_test(&comp->in_flight)))
complete(&comp->comp);
@@ -932,6 +937,7 @@ static void xor_journal(struct dm_integrity_c *ic, bool encrypt, unsigned int se
while (unlikely(pl_index == section_index)) {
unsigned int dummy;
+
if (likely(encrypt))
rw_section_mac(ic, section, true);
section++;
@@ -961,6 +967,7 @@ static void xor_journal(struct dm_integrity_c *ic, bool encrypt, unsigned int se
static void complete_journal_encrypt(struct crypto_async_request *req, int err)
{
struct journal_completion *comp = req->data;
+
if (unlikely(err)) {
if (likely(err == -EINPROGRESS)) {
complete(&comp->ic->crypto_backoff);
@@ -974,6 +981,7 @@ static void complete_journal_encrypt(struct crypto_async_request *req, int err)
static bool do_crypt(bool encrypt, struct skcipher_request *req, struct journal_completion *comp)
{
int r;
+
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
complete_journal_encrypt, comp);
if (likely(encrypt))
@@ -1049,6 +1057,7 @@ static void encrypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned in
static void complete_journal_io(unsigned long error, void *context)
{
struct journal_completion *comp = context;
+
if (unlikely(error != 0))
dm_integrity_io_error(comp->ic, "writing journal", -EIO);
complete_journal_op(comp);
@@ -1139,6 +1148,7 @@ static void write_journal(struct dm_integrity_c *ic, unsigned int commit_start,
commit_sections, &io_comp);
} else {
unsigned int to_end;
+
io_comp.in_flight = (atomic_t)ATOMIC_INIT(2);
to_end = ic->journal_sections - commit_start;
if (ic->journal_io) {
@@ -1228,6 +1238,7 @@ static bool add_new_range(struct dm_integrity_c *ic, struct dm_integrity_range *
if (likely(check_waiting)) {
struct dm_integrity_range *range;
+
list_for_each_entry(range, &ic->wait_list, wait_entry) {
if (unlikely(ranges_overlap(range, new_range)))
return false;
@@ -1262,6 +1273,7 @@ static void remove_range_unlocked(struct dm_integrity_c *ic, struct dm_integrity
struct dm_integrity_range *last_range =
list_first_entry(&ic->wait_list, struct dm_integrity_range, wait_entry);
struct task_struct *last_range_task;
+
last_range_task = last_range->task;
list_del(&last_range->wait_entry);
if (!add_new_range(ic, last_range, false)) {
@@ -1321,6 +1333,7 @@ static void add_journal_node(struct dm_integrity_c *ic, struct journal_node *nod
while (*link) {
struct journal_node *j;
+
parent = *link;
j = container_of(parent, struct journal_node, node);
if (sector < j->sector)
@@ -1346,9 +1359,11 @@ static unsigned int find_journal_node(struct dm_integrity_c *ic, sector_t sector
{
struct rb_node *n = ic->journal_tree_root.rb_node;
unsigned int found = NOT_FOUND;
+
*next_sector = (sector_t)-1;
while (n) {
struct journal_node *j = container_of(n, struct journal_node, node);
+
if (sector == j->sector) {
found = j - ic->journal_tree;
}
@@ -1508,6 +1523,7 @@ struct flush_request {
static void flush_notify(unsigned long error, void *fr_)
{
struct flush_request *fr = fr_;
+
if (unlikely(error != 0))
dm_integrity_io_error(fr->ic, "flushing disk cache", -EIO);
complete(&fr->comp);
@@ -1516,7 +1532,6 @@ static void flush_notify(unsigned long error, void *fr_)
static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_data)
{
int r;
-
struct flush_request fr;
if (!ic->meta_dev)
@@ -1548,6 +1563,7 @@ static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_dat
static void sleep_on_endio_wait(struct dm_integrity_c *ic)
{
DECLARE_WAITQUEUE(wait, current);
+
__add_wait_queue(&ic->endio_wait, &wait);
__set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&ic->endio_wait.lock);
@@ -1585,11 +1601,14 @@ static void submit_flush_bio(struct dm_integrity_c *ic, struct dm_integrity_io *
static void do_endio(struct dm_integrity_c *ic, struct bio *bio)
{
- int r = dm_integrity_failed(ic);
+ int r;
+
+ r = dm_integrity_failed(ic);
if (unlikely(r) && !bio->bi_status)
bio->bi_status = errno_to_blk_status(r);
if (unlikely(ic->synchronous_mode) && bio_op(bio) == REQ_OP_WRITE) {
unsigned long flags;
+
spin_lock_irqsave(&ic->endio_wait.lock, flags);
bio_list_add(&ic->synchronous_bios, bio);
queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0);
@@ -1621,7 +1640,6 @@ static void dec_in_flight(struct dm_integrity_io *dio)
schedule_autocommit(ic);
bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
-
if (unlikely(dio->bi_status) && !bio->bi_status)
bio->bi_status = dio->bi_status;
if (likely(!bio->bi_status) && unlikely(bio_sectors(bio) != dio->range.n_sectors)) {
@@ -1741,10 +1759,12 @@ static void integrity_metadata(struct work_struct *w)
unsigned int bi_size = dio->bio_details.bi_iter.bi_size;
unsigned int max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : HASH_MAX_DIGESTSIZE;
unsigned int max_blocks = max_size / ic->tag_size;
+
memset(checksums, DISCARD_FILLER, max_size);
while (bi_size) {
unsigned int this_step_blocks = bi_size >> (SECTOR_SHIFT + ic->sb->log2_sectors_per_block);
+
this_step_blocks = min(this_step_blocks, max_blocks);
r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset,
this_step_blocks * ic->tag_size, TAG_WRITE);
@@ -1820,6 +1840,7 @@ again:
struct bio_vec biv;
struct bvec_iter iter;
unsigned int data_to_process = dio->range.n_sectors;
+
sector_to_block(ic, data_to_process);
data_to_process *= ic->tag_size;
@@ -1866,8 +1887,10 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
unsigned int log2_max_io_len = __fls(ti->max_io_len);
sector_t start_boundary = sec >> log2_max_io_len;
sector_t end_boundary = (sec + bio_sectors(bio) - 1) >> log2_max_io_len;
+
if (start_boundary < end_boundary) {
sector_t len = ti->max_io_len - (sec & (ti->max_io_len - 1));
+
dm_accept_partial_bio(bio, len);
}
}
@@ -1903,6 +1926,7 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
if (ic->sectors_per_block > 1 && likely(dio->op != REQ_OP_DISCARD)) {
struct bvec_iter iter;
struct bio_vec bv;
+
bio_for_each_segment(bv, bio, iter) {
if (unlikely(bv.bv_len & ((ic->sectors_per_block << SECTOR_SHIFT) - 1))) {
DMERR("Bio vector (%u,%u) is not aligned on %u-sector boundary",
@@ -1916,6 +1940,7 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
if (!ic->internal_hash) {
if (bip) {
unsigned int wanted_tag_size = bio_sectors(bio) >> ic->sb->log2_sectors_per_block;
+
if (ic->log2_tag_size >= 0)
wanted_tag_size <<= ic->log2_tag_size;
else
@@ -2017,6 +2042,7 @@ retry_kmap:
struct bio_vec biv = bvec_iter_bvec(bip->bip_vec, bip->bip_iter);
unsigned int tag_now = min(biv.bv_len, tag_todo);
char *tag_addr;
+
BUG_ON(PageHighMem(biv.bv_page));
tag_addr = bvec_virt(&biv);
if (likely(dio->op == REQ_OP_WRITE))
@@ -2045,8 +2071,10 @@ retry_kmap:
if (ic->internal_hash) {
unsigned int digest_size = crypto_shash_digestsize(ic->internal_hash);
+
if (unlikely(digest_size > ic->tag_size)) {
char checksums_onstack[HASH_MAX_DIGESTSIZE];
+
integrity_sector_checksum(ic, logical_sector, (char *)js, checksums_onstack);
memcpy(journal_entry_tag(ic, je), checksums_onstack, ic->tag_size);
} else
@@ -2106,6 +2134,7 @@ static void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map
struct completion read_comp;
bool discard_retried = false;
bool need_sync_io = ic->internal_hash && dio->op == REQ_OP_READ;
+
if (unlikely(dio->op == REQ_OP_DISCARD) && ic->mode != 'D')
need_sync_io = true;
@@ -2176,6 +2205,7 @@ retry:
goto journal_read_write;
} else {
sector_t next_sector;
+
journal_read_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
if (likely(journal_read_pos == NOT_FOUND)) {
if (unlikely(dio->range.n_sectors > next_sector - dio->range.logical_sector))
@@ -2183,6 +2213,7 @@ retry:
} else {
unsigned int i;
unsigned int jp = journal_read_pos + 1;
+
for (i = ic->sectors_per_block; i < dio->range.n_sectors; i += ic->sectors_per_block, jp++) {
if (!test_journal_node(ic, jp, dio->range.logical_sector + i))
break;
@@ -2214,7 +2245,9 @@ offload_to_thread:
*/
if (journal_read_pos != NOT_FOUND) {
sector_t next_sector;
- unsigned int new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
+ unsigned int new_pos;
+
+ new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
if (unlikely(new_pos != journal_read_pos)) {
remove_range_unlocked(ic, &dio->range);
goto retry;
@@ -2223,7 +2256,9 @@ offload_to_thread:
}
if (ic->mode == 'J' && likely(dio->op == REQ_OP_DISCARD) && !discard_retried) {
sector_t next_sector;
- unsigned int new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
+ unsigned int new_pos;
+
+ new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
if (unlikely(new_pos != NOT_FOUND) ||
unlikely(next_sector < dio->range.logical_sector - dio->range.n_sectors)) {
remove_range_unlocked(ic, &dio->range);
@@ -2377,11 +2412,13 @@ static void integrity_commit(struct work_struct *w)
for (n = 0; n < commit_sections; n++) {
for (j = 0; j < ic->journal_section_entries; j++) {
struct journal_entry *je;
+
je = access_journal_entry(ic, i, j);
io_wait_event(ic->copy_to_journal_wait, !journal_entry_is_inprogress(je));
}
for (j = 0; j < ic->journal_section_sectors; j++) {
struct journal_sector *js;
+
js = access_journal(ic, i, j);
js->commit_id = dm_integrity_commit_id(ic, i, j, ic->commit_seq);
}
@@ -2407,6 +2444,7 @@ static void integrity_commit(struct work_struct *w)
release_flush_bios:
while (flushes) {
struct bio *next = flushes->bi_next;
+
flushes->bi_next = NULL;
do_endio(ic, flushes);
flushes = next;
@@ -2418,6 +2456,7 @@ static void complete_copy_from_journal(unsigned long error, void *context)
struct journal_io *io = context;
struct journal_completion *comp = io->comp;
struct dm_integrity_c *ic = comp->ic;
+
remove_range(ic, &io->range);
mempool_free(io, &ic->journal_io_mempool);
if (unlikely(error != 0))
@@ -2429,6 +2468,7 @@ static void restore_last_bytes(struct dm_integrity_c *ic, struct journal_sector
struct journal_entry *je)
{
unsigned int s = 0;
+
do {
js->commit_id = je->last_bytes[s];
js++;
@@ -2481,6 +2521,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned int write_start
for (k = j + 1; k < ic->journal_section_entries; k++) {
struct journal_entry *je2 = access_journal_entry(ic, i, k);
sector_t sec2, area2, offset2;
+
if (journal_entry_is_unused(je2))
break;
BUG_ON(unlikely(journal_entry_is_inprogress(je2)) && !from_replay);
@@ -2586,7 +2627,6 @@ static void integrity_writer(struct work_struct *w)
{
struct dm_integrity_c *ic = container_of(w, struct dm_integrity_c, writer_work);
unsigned int write_start, write_sections;
-
unsigned int prev_free_sectors;
spin_lock_irq(&ic->endio_wait.lock);
@@ -2732,6 +2772,7 @@ next_chunk:
if (ic->mode == 'B') {
sector_t start, end;
+
start = (range.logical_sector >>
(ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit)) <<
(ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
@@ -2867,12 +2908,14 @@ static void init_journal(struct dm_integrity_c *ic, unsigned int start_section,
wraparound_section(ic, &i);
for (j = 0; j < ic->journal_section_sectors; j++) {
struct journal_sector *js = access_journal(ic, i, j);
+
BUILD_BUG_ON(sizeof(js->sectors) != JOURNAL_SECTOR_DATA);
memset(&js->sectors, 0, sizeof(js->sectors));
js->commit_id = dm_integrity_commit_id(ic, i, j, commit_seq);
}
for (j = 0; j < ic->journal_section_entries; j++) {
struct journal_entry *je = access_journal_entry(ic, i, j);
+
journal_entry_set_unused(je);
}
}
@@ -2883,6 +2926,7 @@ static void init_journal(struct dm_integrity_c *ic, unsigned int start_section,
static int find_commit_seq(struct dm_integrity_c *ic, unsigned int i, unsigned int j, commit_id_t id)
{
unsigned char k;
+
for (k = 0; k < N_COMMIT_IDS; k++) {
if (dm_integrity_commit_id(ic, i, j, k) == id)
return k;
@@ -2917,6 +2961,7 @@ static void replay_journal(struct dm_integrity_c *ic)
DEBUG_bytes(lowmem_page_address(ic->journal_io[0].page), 64, "read journal");
if (ic->journal_io) {
struct journal_completion crypt_comp;
+
crypt_comp.ic = ic;
init_completion(&crypt_comp.comp);
crypt_comp.in_flight = (atomic_t)ATOMIC_INIT(0);
@@ -2936,6 +2981,7 @@ static void replay_journal(struct dm_integrity_c *ic)
for (j = 0; j < ic->journal_section_sectors; j++) {
int k;
struct journal_sector *js = access_journal(ic, i, j);
+
k = find_commit_seq(ic, i, j, js->commit_id);
if (k < 0)
goto clear_journal;
@@ -2945,6 +2991,7 @@ static void replay_journal(struct dm_integrity_c *ic)
if (jour