diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-07 17:23:00 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-07 17:23:00 +0200 |
| commit | dcf5b8a7ae4e3875878529597c05f8cac4121515 (patch) | |
| tree | 0d86567a8feacb35b2a62c1ba6cf6c2fe3be65de /drivers/md | |
| parent | 864c971e923f55d3ff5ac3ebc87aab8108d30c8a (diff) | |
| parent | 7cfc41f8e80f11ffa8382ed1a505154ceffb79c7 (diff) | |
Merge v6.18.50linux-rolling-lts
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/md')
| -rw-r--r-- | drivers/md/dm-bufio.c | 10 | ||||
| -rw-r--r-- | drivers/md/dm-era-target.c | 5 | ||||
| -rw-r--r-- | drivers/md/dm-integrity.c | 32 | ||||
| -rw-r--r-- | drivers/md/dm-io.c | 96 | ||||
| -rw-r--r-- | drivers/md/dm-kcopyd.c | 10 | ||||
| -rw-r--r-- | drivers/md/dm-log-userspace-base.c | 1 | ||||
| -rw-r--r-- | drivers/md/dm-log.c | 4 | ||||
| -rw-r--r-- | drivers/md/dm-pcache/cache.c | 18 | ||||
| -rw-r--r-- | drivers/md/dm-pcache/cache.h | 21 | ||||
| -rw-r--r-- | drivers/md/dm-pcache/cache_dev.c | 22 | ||||
| -rw-r--r-- | drivers/md/dm-pcache/cache_gc.c | 10 | ||||
| -rw-r--r-- | drivers/md/dm-pcache/cache_key.c | 32 | ||||
| -rw-r--r-- | drivers/md/dm-pcache/cache_segment.c | 12 | ||||
| -rw-r--r-- | drivers/md/dm-pcache/cache_writeback.c | 10 | ||||
| -rw-r--r-- | drivers/md/dm-pcache/dm_pcache.c | 4 | ||||
| -rw-r--r-- | drivers/md/dm-raid1.c | 26 | ||||
| -rw-r--r-- | drivers/md/dm-snap-persistent.c | 4 | ||||
| -rw-r--r-- | drivers/md/dm-stats.c | 6 | ||||
| -rw-r--r-- | drivers/md/dm-switch.c | 2 | ||||
| -rw-r--r-- | drivers/md/dm-verity-target.c | 2 | ||||
| -rw-r--r-- | drivers/md/dm-writecache.c | 14 | ||||
| -rw-r--r-- | drivers/md/md.c | 7 | ||||
| -rw-r--r-- | drivers/md/persistent-data/dm-array.c | 53 | ||||
| -rw-r--r-- | drivers/md/raid10.c | 2 |
24 files changed, 272 insertions, 131 deletions
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index b7cbe5874094..59e5d8aa42b7 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1282,11 +1282,11 @@ static void free_buffer(struct dm_buffer *b) * dm-io completion routine. It just calls b->bio.bi_end_io, pretending * that the request was handled directly with bio interface. */ -static void dmio_complete(unsigned long error, void *context) +static void dmio_complete(unsigned long error, unsigned long unsup, void *context) { struct dm_buffer *b = context; - b->end_io(b, unlikely(error != 0) ? BLK_STS_IOERR : 0); + b->end_io(b, unlikely(error != 0) ? BLK_STS_IOERR : unlikely(unsup != 0) ? BLK_STS_NOTSUPP : 0); } static void use_dmio(struct dm_buffer *b, enum req_op op, sector_t sector, @@ -1314,7 +1314,7 @@ static void use_dmio(struct dm_buffer *b, enum req_op op, sector_t sector, io_req.mem.ptr.vma = (char *)b->data + offset; } - r = dm_io(&io_req, 1, ®ion, NULL, ioprio); + r = dm_io(&io_req, 1, ®ion, NULL, NULL, ioprio); if (unlikely(r)) b->end_io(b, errno_to_blk_status(r)); } @@ -2197,7 +2197,7 @@ int dm_bufio_issue_flush(struct dm_bufio_client *c) if (WARN_ON_ONCE(dm_bufio_in_request())) return -EINVAL; - return dm_io(&io_req, 1, &io_reg, NULL, IOPRIO_DEFAULT); + return dm_io(&io_req, 1, &io_reg, NULL, NULL, IOPRIO_DEFAULT); } EXPORT_SYMBOL_GPL(dm_bufio_issue_flush); @@ -2223,7 +2223,7 @@ int dm_bufio_issue_discard(struct dm_bufio_client *c, sector_t block, sector_t c if (WARN_ON_ONCE(dm_bufio_in_request())) return -EINVAL; /* discards are optional */ - return dm_io(&io_req, 1, &io_reg, NULL, IOPRIO_DEFAULT); + return dm_io(&io_req, 1, &io_reg, NULL, NULL, IOPRIO_DEFAULT); } EXPORT_SYMBOL_GPL(dm_bufio_issue_discard); diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c index 883d1549cfc0..6f87e2c4e7da 100644 --- a/drivers/md/dm-era-target.c +++ b/drivers/md/dm-era-target.c @@ -1034,6 +1034,7 @@ static int metadata_checkpoint(struct era_metadata *md) static int metadata_take_snap(struct era_metadata *md) { int r, inc; + dm_block_t location; struct dm_block *clone; if (md->metadata_snap != SUPERBLOCK_LOCATION) { @@ -1071,7 +1072,9 @@ static int metadata_take_snap(struct era_metadata *md) r = dm_sm_inc_block(md->sm, md->writeset_tree_root); if (r) { DMERR("%s: couldn't inc writeset tree root", __func__); + location = dm_block_location(clone); dm_tm_unlock(md->tm, clone); + dm_sm_dec_block(md->sm, location); return r; } @@ -1079,7 +1082,9 @@ static int metadata_take_snap(struct era_metadata *md) if (r) { DMERR("%s: couldn't inc era tree root", __func__); dm_sm_dec_block(md->sm, md->writeset_tree_root); + location = dm_block_location(clone); dm_tm_unlock(md->tm, clone); + dm_sm_dec_block(md->sm, location); return r; } diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index cd602b39481d..46a815f20b09 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -561,7 +561,7 @@ static int sync_rw_sb(struct dm_integrity_c *ic, blk_opf_t opf) } } - r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + r = dm_io(&io_req, 1, &io_loc, NULL, NULL, IOPRIO_DEFAULT); if (unlikely(r)) return r; @@ -1034,12 +1034,14 @@ static void encrypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned in return crypt_journal(ic, encrypt, section, n_sections, comp); } -static void complete_journal_io(unsigned long error, void *context) +static void complete_journal_io(unsigned long error, unsigned long unsup, void *context) { struct journal_completion *comp = context; if (unlikely(error != 0)) dm_integrity_io_error(comp->ic, "writing journal", -EIO); + else if (unlikely(unsup != 0)) + dm_integrity_io_error(comp->ic, "writing journal", -EOPNOTSUPP); complete_journal_op(comp); } @@ -1054,7 +1056,7 @@ static void rw_journal_sectors(struct dm_integrity_c *ic, blk_opf_t opf, if (unlikely(dm_integrity_failed(ic))) { if (comp) - complete_journal_io(-1UL, comp); + complete_journal_io(-1UL, -1UL, comp); return; } @@ -1079,13 +1081,13 @@ static void rw_journal_sectors(struct dm_integrity_c *ic, blk_opf_t opf, io_loc.sector = ic->start + SB_SECTORS + sector; io_loc.count = n_sectors; - r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + r = dm_io(&io_req, 1, &io_loc, NULL, NULL, IOPRIO_DEFAULT); if (unlikely(r)) { dm_integrity_io_error(ic, (opf & REQ_OP_MASK) == REQ_OP_READ ? "reading journal" : "writing journal", r); if (comp) { WARN_ONCE(1, "asynchronous dm_io failed: %d", r); - complete_journal_io(-1UL, comp); + complete_journal_io(-1UL, -1UL, comp); } } } @@ -1176,7 +1178,7 @@ static void copy_from_journal(struct dm_integrity_c *ic, unsigned int section, u BUG_ON((target | n_sectors | offset) & (unsigned int)(ic->sectors_per_block - 1)); if (unlikely(dm_integrity_failed(ic))) { - fn(-1UL, data); + fn(-1UL, -1UL, data); return; } @@ -1196,10 +1198,10 @@ static void copy_from_journal(struct dm_integrity_c *ic, unsigned int section, u io_loc.sector = target; io_loc.count = n_sectors; - r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + r = dm_io(&io_req, 1, &io_loc, NULL, NULL, IOPRIO_DEFAULT); if (unlikely(r)) { WARN_ONCE(1, "asynchronous dm_io failed: %d", r); - fn(-1UL, data); + fn(-1UL, -1UL, data); } } @@ -1492,12 +1494,14 @@ struct flush_request { struct completion comp; }; -static void flush_notify(unsigned long error, void *fr_) +static void flush_notify(unsigned long error, unsigned long unsup, void *fr_) { struct flush_request *fr = fr_; if (unlikely(error != 0)) dm_integrity_io_error(fr->ic, "flushing disk cache", -EIO); + else if (unlikely(unsup != 0)) + dm_integrity_io_error(fr->ic, "flushing disk cache", -EOPNOTSUPP); complete(&fr->comp); } @@ -1520,7 +1524,7 @@ static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_dat fr.io_reg.count = 0; fr.ic = ic; init_completion(&fr.comp); - r = dm_io(&fr.io_req, 1, &fr.io_reg, NULL, IOPRIO_DEFAULT); + r = dm_io(&fr.io_req, 1, &fr.io_reg, NULL, NULL, IOPRIO_DEFAULT); BUG_ON(r); } @@ -1836,7 +1840,7 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks buffer_offset = (sector - io_loc.sector) << SECTOR_SHIFT; io_loc.count = round_up(io_loc.count, alignment); - r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + r = dm_io(&io_req, 1, &io_loc, NULL, NULL, IOPRIO_DEFAULT); if (unlikely(r)) { dio->bi_status = errno_to_blk_status(r); goto free_ret; @@ -2889,7 +2893,7 @@ release_flush_bios: } } -static void complete_copy_from_journal(unsigned long error, void *context) +static void complete_copy_from_journal(unsigned long error, unsigned long unsup, void *context) { struct journal_io *io = context; struct journal_completion *comp = io->comp; @@ -2899,6 +2903,8 @@ static void complete_copy_from_journal(unsigned long error, void *context) mempool_free(io, &ic->journal_io_mempool); if (unlikely(error != 0)) dm_integrity_io_error(ic, "copying from journal", -EIO); + else if (unlikely(unsup != 0)) + dm_integrity_io_error(ic, "copying from journal", -EOPNOTSUPP); complete_journal_op(comp); } @@ -3214,7 +3220,7 @@ next_chunk: io_loc.sector = get_data_sector(ic, area, offset); io_loc.count = n_sectors; - r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + r = dm_io(&io_req, 1, &io_loc, NULL, NULL, IOPRIO_DEFAULT); if (unlikely(r)) { dm_integrity_io_error(ic, "reading data", r); goto err; diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index c37668790577..c6684e63ceb0 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -33,6 +33,7 @@ struct dm_io_client { */ struct io { unsigned long error_bits; + unsigned long unsup_bits; atomic_t count; struct dm_io_client *client; io_notify_fn callback; @@ -119,6 +120,7 @@ static void retrieve_io_and_region_from_bio(struct bio *bio, struct io **io, static void complete_io(struct io *io) { unsigned long error_bits = io->error_bits; + unsigned long unsup_bits = io->unsup_bits; io_notify_fn fn = io->callback; void *context = io->context; @@ -127,13 +129,17 @@ static void complete_io(struct io *io) io->vma_invalidate_size); mempool_free(io, &io->client->pool); - fn(error_bits, context); + fn(error_bits, unsup_bits, context); } static void dec_count(struct io *io, unsigned int region, blk_status_t error) { - if (error) - set_bit(region, &io->error_bits); + if (unlikely(error)) { + if (error == BLK_STS_NOTSUPP || error == BLK_STS_INVAL) + set_bit(region, &io->unsup_bits); + else + set_bit(region, &io->error_bits); + } if (atomic_dec_and_test(&io->count)) complete_io(io); @@ -170,12 +176,11 @@ struct dpages { struct page **p, unsigned long *len, unsigned int *offset); void (*next_page)(struct dpages *dp); - union { - unsigned int context_u; - struct bvec_iter context_bi; - }; + unsigned int context_u; void *context_ptr; + struct bio *orig_bio; + void *vma_invalidate_address; unsigned long vma_invalidate_size; }; @@ -211,44 +216,6 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned int o } /* - * Functions for getting the pages from a bvec. - */ -static void bio_get_page(struct dpages *dp, struct page **p, - unsigned long *len, unsigned int *offset) -{ - struct bio_vec bvec = bvec_iter_bvec((struct bio_vec *)dp->context_ptr, - dp->context_bi); - - *p = bvec.bv_page; - *len = bvec.bv_len; - *offset = bvec.bv_offset; - - /* avoid figuring it out again in bio_next_page() */ - dp->context_bi.bi_sector = (sector_t)bvec.bv_len; -} - -static void bio_next_page(struct dpages *dp) -{ - unsigned int len = (unsigned int)dp->context_bi.bi_sector; - - bvec_iter_advance((struct bio_vec *)dp->context_ptr, - &dp->context_bi, len); -} - -static void bio_dp_init(struct dpages *dp, struct bio *bio) -{ - dp->get_page = bio_get_page; - dp->next_page = bio_next_page; - - /* - * We just use bvec iterator to retrieve pages, so it is ok to - * access the bvec table directly here - */ - dp->context_ptr = bio->bi_io_vec; - dp->context_bi = bio->bi_iter; -} - -/* * Functions for getting the pages from a VMA. */ static void vm_get_page(struct dpages *dp, @@ -332,6 +299,21 @@ static void do_region(const blk_opf_t opf, unsigned int region, return; } + if (dp->orig_bio) { + bio = bio_alloc_clone(where->bdev, dp->orig_bio, GFP_NOIO, + &io->client->bios); + bio->bi_iter.bi_sector = where->sector; + bio->bi_iter.bi_size = where->count << SECTOR_SHIFT; + bio->bi_opf = opf; + bio->bi_end_io = endio; + bio->bi_ioprio = ioprio; + store_io_and_region_in_bio(bio, io, region); + + atomic_inc(&io->count); + submit_bio(bio); + return; + } + /* * where->count may be zero if op holds a flush and we need to * send a zero-sized flush. @@ -418,6 +400,7 @@ static void async_io(struct dm_io_client *client, unsigned int num_regions, io = mempool_alloc(&client->pool, GFP_NOIO); io->error_bits = 0; + io->unsup_bits = 0; atomic_set(&io->count, 1); /* see dispatch_io() */ io->client = client; io->callback = fn; @@ -431,20 +414,23 @@ static void async_io(struct dm_io_client *client, unsigned int num_regions, struct sync_io { unsigned long error_bits; + unsigned long unsup_bits; struct completion wait; }; -static void sync_io_complete(unsigned long error, void *context) +static void sync_io_complete(unsigned long error, unsigned long unsup, void *context) { struct sync_io *sio = context; sio->error_bits = error; + sio->unsup_bits = unsup; complete(&sio->wait); } static int sync_io(struct dm_io_client *client, unsigned int num_regions, struct dm_io_region *where, blk_opf_t opf, struct dpages *dp, - unsigned long *error_bits, unsigned short ioprio) + unsigned long *error_bits, unsigned long *unsup_bits, + unsigned short ioprio) { struct sync_io sio; @@ -457,8 +443,10 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, if (error_bits) *error_bits = sio.error_bits; + if (unsup_bits) + *unsup_bits = sio.unsup_bits; - return sio.error_bits ? -EIO : 0; + return sio.error_bits ? -EIO : sio.unsup_bits ? -EOPNOTSUPP : 0; } static int dp_init(struct dm_io_request *io_req, struct dpages *dp, @@ -468,6 +456,7 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp, dp->vma_invalidate_address = NULL; dp->vma_invalidate_size = 0; + dp->orig_bio = NULL; switch (io_req->mem.type) { case DM_IO_PAGE_LIST: @@ -475,7 +464,11 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp, break; case DM_IO_BIO: - bio_dp_init(dp, io_req->mem.ptr.bio); + /* + * The destination bios clone this bio's biovec directly, so + * there are no per-page accessors to set up here. + */ + dp->orig_bio = io_req->mem.ptr.bio; break; case DM_IO_VMA: @@ -500,7 +493,7 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp, int dm_io(struct dm_io_request *io_req, unsigned int num_regions, struct dm_io_region *where, unsigned long *sync_error_bits, - unsigned short ioprio) + unsigned long *sync_unsup_bits, unsigned short ioprio) { int r; struct dpages dp; @@ -516,7 +509,8 @@ int dm_io(struct dm_io_request *io_req, unsigned int num_regions, if (!io_req->notify.fn) return sync_io(io_req->client, num_regions, where, - io_req->bi_opf, &dp, sync_error_bits, ioprio); + io_req->bi_opf, &dp, sync_error_bits, + sync_unsup_bits, ioprio); async_io(io_req->client, num_regions, where, io_req->bi_opf, &dp, io_req->notify.fn, io_req->notify.context, ioprio); diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index cec9a60227b6..7eecce8711ce 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -517,16 +517,16 @@ static int run_complete_job(struct kcopyd_job *job) return 0; } -static void complete_io(unsigned long error, void *context) +static void complete_io(unsigned long error, unsigned long unsup, void *context) { struct kcopyd_job *job = context; struct dm_kcopyd_client *kc = job->kc; io_job_finish(kc->throttle); - if (error) { + if (unlikely((error | unsup) != 0)) { if (op_is_write(job->op)) - job->write_err |= error; + job->write_err |= error | unsup; else job->read_err = 1; @@ -578,9 +578,9 @@ static int run_io_job(struct kcopyd_job *job) io_job_start(job->kc->throttle); if (job->op == REQ_OP_READ) - r = dm_io(&io_req, 1, &job->source, NULL, IOPRIO_DEFAULT); + r = dm_io(&io_req, 1, &job->source, NULL, NULL, IOPRIO_DEFAULT); else - r = dm_io(&io_req, job->num_dests, job->dests, NULL, IOPRIO_DEFAULT); + r = dm_io(&io_req, job->num_dests, job->dests, NULL, NULL, IOPRIO_DEFAULT); return r; } diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 607436804a8b..40e21bec4792 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -139,6 +139,7 @@ static int build_constructor_string(struct dm_target *ti, str_size += strlen(argv[i]) + 1; /* +1 for space between args */ str_size += 20; /* Max number of chars in a printed u64 number */ + str_size++; /* For NUL-terminator */ str = kzalloc(str_size, GFP_KERNEL); if (!str) { diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index c8a1f9b6385f..38b686a7a487 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -300,7 +300,7 @@ static int rw_header(struct log_c *lc, enum req_op op) { lc->io_req.bi_opf = op; - return dm_io(&lc->io_req, 1, &lc->header_location, NULL, IOPRIO_DEFAULT); + return dm_io(&lc->io_req, 1, &lc->header_location, NULL, NULL, IOPRIO_DEFAULT); } static int flush_header(struct log_c *lc) @@ -313,7 +313,7 @@ static int flush_header(struct log_c *lc) lc->io_req.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH; - return dm_io(&lc->io_req, 1, &null_location, NULL, IOPRIO_DEFAULT); + return dm_io(&lc->io_req, 1, &null_location, NULL, NULL, IOPRIO_DEFAULT); } static int read_header(struct log_c *log) diff --git a/drivers/md/dm-pcache/cache.c b/drivers/md/dm-pcache/cache.c index 534bf07b794f..887157fde68d 100644 --- a/drivers/md/dm-pcache/cache.c +++ b/drivers/md/dm-pcache/cache.c @@ -119,6 +119,10 @@ int cache_pos_decode(struct pcache_cache *cache, return -EIO; pos->cache_seg = &cache->segments[latest.cache_seg_id]; + + if (latest.seg_off >= pos->cache_seg->segment.data_size) + return -EIO; + pos->seg_off = latest.seg_off; *seq = latest.header.seq; *index = (latest_addr - pos_onmedia); @@ -246,6 +250,13 @@ static int get_seg_id(struct pcache_cache *cache, } else { *seg_id = cache->cache_info.seg_id; } + + if (*seg_id >= cache_dev->seg_num) { + pcache_dev_err(pcache, "invalid segment id %u from cache device (seg_num %u)\n", + *seg_id, cache_dev->seg_num); + ret = -EIO; + goto err; + } } return 0; err: @@ -261,6 +272,13 @@ static int cache_segs_init(struct pcache_cache *cache) int ret; u32 i; + if (cache_info->n_segs > cache->cache_dev->seg_num) { + pcache_dev_err(CACHE_TO_PCACHE(cache), + "cache_info n_segs %u exceeds cache device segments %u\n", + cache_info->n_segs, cache->cache_dev->seg_num); + return -EIO; + } + for (i = 0; i < cache_info->n_segs; i++) { ret = get_seg_id(cache, prev_cache_seg, new_cache, &seg_id); if (ret) diff --git a/drivers/md/dm-pcache/cache.h b/drivers/md/dm-pcache/cache.h index 27613b56be54..afc112b79496 100644 --- a/drivers/md/dm-pcache/cache.h +++ b/drivers/md/dm-pcache/cache.h @@ -491,6 +491,27 @@ static inline u32 cache_key_data_crc(struct pcache_cache_key *key) return crc32c(PCACHE_CRC_SEED, data, key->len); } +/** + * kset_onmedia_valid - Validate a kset header read from the cache device. + * @kset_onmedia: Pointer to the kset copied from on-media metadata. + * + * The magic and CRC are attacker-computable (fixed public seed). A non-last + * kset stores key_num keys inline, and cache_kset_crc() and the replay loop + * read struct_size(.., data, key_num) bytes from a buffer sized for + * PCACHE_KSET_KEYS_MAX keys, so key_num must be bounded before any such use. + */ +static inline bool kset_onmedia_valid(struct pcache_cache_kset_onmedia *kset_onmedia) +{ + if (kset_onmedia->magic != PCACHE_KSET_MAGIC) + return false; + + if (!(kset_onmedia->flags & PCACHE_KSET_FLAGS_LAST) && + kset_onmedia->key_num > PCACHE_KSET_KEYS_MAX) + return false; + + return true; +} + static inline u32 cache_kset_crc(struct pcache_cache_kset_onmedia *kset_onmedia) { u32 crc_size; diff --git a/drivers/md/dm-pcache/cache_dev.c b/drivers/md/dm-pcache/cache_dev.c index ece689e6ce59..f0259353ee39 100644 --- a/drivers/md/dm-pcache/cache_dev.c +++ b/drivers/md/dm-pcache/cache_dev.c @@ -242,6 +242,8 @@ int cache_dev_start(struct dm_pcache *pcache) struct pcache_cache_dev *cache_dev = &pcache->cache_dev; struct pcache_sb sb; bool format = false; + u32 seg_num; + u64 max_segs; int ret; mutex_init(&cache_dev->seg_lock); @@ -269,7 +271,25 @@ int cache_dev_start(struct dm_pcache *pcache) goto dax_release; cache_dev->sb_flags = le32_to_cpu(sb.flags); - ret = cache_dev_init(cache_dev, le32_to_cpu(sb.seg_num)); + + /* + * seg_num is read from the crc32c-only superblock, so whoever supplies + * the cache device controls it. It is the ceiling every later on-media + * segment id is validated against, so bound it against what the device + * physically holds before it is trusted, or a forged seg_num lets a + * segment id address past the DAX mapping. + */ + seg_num = le32_to_cpu(sb.seg_num); + max_segs = (bdev_nr_bytes(cache_dev->dm_dev->bdev) - PCACHE_SEGMENTS_OFF) / + PCACHE_SEG_SIZE; + if (seg_num == 0 || seg_num > max_segs || seg_num > PCACHE_CACHE_SEGS_MAX) { + pcache_dev_err(pcache, "invalid seg_num %u from cache device (device holds %llu, max %u)\n", + seg_num, max_segs, (u32)PCACHE_CACHE_SEGS_MAX); + ret = -EIO; + goto dax_release; + } + + ret = cache_dev_init(cache_dev, seg_num); if (ret) goto dax_release; diff --git a/drivers/md/dm-pcache/cache_gc.c b/drivers/md/dm-pcache/cache_gc.c index 94f8b276a021..3088cfef951b 100644 --- a/drivers/md/dm-pcache/cache_gc.c +++ b/drivers/md/dm-pcache/cache_gc.c @@ -37,18 +37,18 @@ static bool need_gc(struct pcache_cache *cache, struct pcache_cache_pos *dirty_t kset_onmedia = (struct pcache_cache_kset_onmedia *)cache->gc_kset_onmedia_buf; - to_copy = min(PCACHE_KSET_ONMEDIA_SIZE_MAX, PCACHE_SEG_SIZE - key_tail->seg_off); + to_copy = min(PCACHE_KSET_ONMEDIA_SIZE_MAX, cache_seg_remain(key_tail)); ret = copy_mc_to_kernel(kset_onmedia, key_addr, to_copy); if (ret) { pcache_dev_err(pcache, "error to read kset: %d", ret); return false; } - /* Check if kset_onmedia is corrupted */ - if (kset_onmedia->magic != PCACHE_KSET_MAGIC) { - pcache_dev_debug(pcache, "gc error: magic is not as expected. key_tail: %u:%u magic: %llx, expected: %llx\n", + /* Reject a corrupted or out-of-bounds kset before reading its keys */ + if (!kset_onmedia_valid(kset_onmedia)) { + pcache_dev_debug(pcache, "gc error: invalid kset. key_tail: %u:%u magic: %llx, key_num: %u\n", key_tail->cache_seg->cache_seg_id, key_tail->seg_off, - kset_onmedia->magic, PCACHE_KSET_MAGIC); + kset_onmedia->magic, kset_onmedia->key_num); return false; } diff --git a/drivers/md/dm-pcache/cache_key.c b/drivers/md/dm-pcache/cache_key.c index 2b77e121f89b..a3bb1f95afb9 100644 --- a/drivers/md/dm-pcache/cache_key.c +++ b/drivers/md/dm-pcache/cache_key.c @@ -97,6 +97,14 @@ int cache_key_decode(struct pcache_cache *cache, key->cache_pos.cache_seg = &cache->segments[key_onmedia->cache_seg_id]; key->cache_pos.seg_off = key_onmedia->cache_seg_off; + if ((u64)key->cache_pos.seg_off + key->len > + key->cache_pos.cache_seg->segment.data_size) { + pcache_dev_err(pcache, "key seg_off %u + len %u exceeds segment data size %u\n", + key->cache_pos.seg_off, key->len, + key->cache_pos.cache_seg->segment.data_size); + return -EIO; + } + key->seg_gen = key_onmedia->seg_gen; key->flags = key_onmedia->flags; @@ -728,18 +736,17 @@ static int kset_replay(struct pcache_cache *cache, struct pcache_cache_kset_onme goto err; } - __set_bit(key->cache_pos.cache_seg->cache_seg_id, cache->seg_map); - /* Check if the segment generation is valid for insertion. */ if (key->seg_gen < key->cache_pos.cache_seg->gen) { cache_key_put(key); - } else { - cache_subtree = get_subtree(&cache->req_key_tree, key->off); - spin_lock(&cache_subtree->tree_lock); - cache_key_insert(&cache->req_key_tree, key, true); - spin_unlock(&cache_subtree->tree_lock); + continue; } + __set_bit(key->cache_pos.cache_seg->cache_seg_id, cache->seg_map); + cache_subtree = get_subtree(&cache->req_key_tree, key->off); + spin_lock(&cache_subtree->tree_lock); + cache_key_insert(&cache->req_key_tree, key, true); + spin_unlock(&cache_subtree->tree_lock); cache_seg_get(key->cache_pos.cache_seg); } @@ -754,7 +761,7 @@ int cache_replay(struct pcache_cache *cache) struct pcache_cache_pos pos_tail; struct pcache_cache_pos *pos; struct pcache_cache_kset_onmedia *kset_onmedia; - u32 to_copy, count = 0; + u32 to_copy, count = 0, last_hops = 0; int ret = 0; kset_onmedia = kzalloc(PCACHE_KSET_ONMEDIA_SIZE_MAX, GFP_KERNEL); @@ -771,14 +778,14 @@ int cache_replay(struct pcache_cache *cache) __set_bit(pos->cache_seg->cache_seg_id, cache->seg_map); while (true) { - to_copy = min(PCACHE_KSET_ONMEDIA_SIZE_MAX, PCACHE_SEG_SIZE - pos->seg_off); + to_copy = min(PCACHE_KSET_ONMEDIA_SIZE_MAX, cache_seg_remain(pos)); ret = copy_mc_to_kernel(kset_onmedia, cache_pos_addr(pos), to_copy); if (ret) { ret = -EIO; goto out; } - if (kset_onmedia->magic != PCACHE_KSET_MAGIC || + if (!kset_onmedia_valid(kset_onmedia) || kset_onmedia->crc != cache_kset_crc(kset_onmedia)) { break; } @@ -789,6 +796,11 @@ int cache_replay(struct pcache_cache *cache) pcache_dev_debug(pcache, "last kset replay, next: %u\n", kset_onmedia->next_cache_seg_id); + if (++last_hops > cache->n_segs) { + ret = -EIO; + goto out; + } + next_seg = &cache->segments[kset_onmedia->next_cache_seg_id]; pos->cache_seg = next_seg; diff --git a/drivers/md/dm-pcache/cache_segment.c b/drivers/md/dm-pcache/cache_segment.c index 9d92e2b067ed..c698ebbc626d 100644 --- a/drivers/md/dm-pcache/cache_segment.c +++ b/drivers/md/dm-pcache/cache_segment.c @@ -243,8 +243,16 @@ struct pcache_cache_segment *get_cache_segment(struct pcache_cache *cache) spin_lock(&cache->seg_map_lock); again: - seg_id = find_next_zero_bit(cache->seg_map, cache->n_segs, cache->last_cache_seg); - if (seg_id == cache->n_segs) { + /* + * Only allocate initialized segments. cache_segs_init() initializes + * cache_info.n_segs of the cache->n_segs device segments; a forged + * smaller cache_info.n_segs leaves the rest as zeroed structs whose data + * pointer is NULL. Bounding the search to cache_info.n_segs keeps such a + * segment from reaching cache_kset_close(), which writes through it. + */ + seg_id = find_next_zero_bit(cache->seg_map, cache->cache_info.n_segs, + cache->last_cache_seg); + if (seg_id == cache->cache_info.n_segs) { /* reset the hint of ->last_cache_seg and retry */ if (cache->last_cache_seg) { cache->last_cache_seg = 0; diff --git a/drivers/md/dm-pcache/cache_writeback.c b/drivers/md/dm-pcache/cache_writeback.c index 87a82b3fe836..3df8687e2382 100644 --- a/drivers/md/dm-pcache/cache_writeback.c +++ b/drivers/md/dm-pcache/cache_writeback.c @@ -48,18 +48,18 @@ static inline bool is_cache_clean(struct pcache_cache *cache, struct pcache_cach addr = cache_pos_addr(dirty_tail); kset_onmedia = (struct pcache_cache_kset_onmedia *)cache->wb_kset_onmedia_buf; - to_copy = min(PCACHE_KSET_ONMEDIA_SIZE_MAX, PCACHE_SEG_SIZE - dirty_tail->seg_off); + to_copy = min(PCACHE_KSET_ONMEDIA_SIZE_MAX, cache_seg_remain(dirty_tail)); ret = copy_mc_to_kernel(kset_onmedia, addr, to_copy); if (ret) { pcache_dev_err(pcache, "error to read kset: %d", ret); return true; } - /* Check if the magic number matches the expected value */ - if (kset_onmedia->magic != PCACHE_KSET_MAGIC) { - pcache_dev_debug(pcache, "dirty_tail: %u:%u magic: %llx, not expected: %llx\n", + /* Reject a corrupted or out-of-bounds kset before reading its keys */ + if (!kset_onmedia_valid(kset_onmedia)) { + pcache_dev_debug(pcache, "dirty_tail: %u:%u invalid kset magic: %llx, key_num: %u\n", dirty_tail->cache_seg->cache_seg_id, dirty_tail->seg_off, - kset_onmedia->magic, PCACHE_KSET_MAGIC); + kset_onmedia->magic, kset_onmedia->key_num); return true; } diff --git a/drivers/md/dm-pcache/dm_pcache.c b/drivers/md/dm-pcache/dm_pcache.c index 87bcc1c515a6..f6da50b57c67 100644 --- a/drivers/md/dm-pcache/dm_pcache.c +++ b/drivers/md/dm-pcache/dm_pcache.c @@ -439,13 +439,13 @@ static int dm_pcache_message(struct dm_target *ti, unsigned int argc, char **argv, char *result, unsigned int maxlen) { struct dm_pcache *pcache = ti->private; - unsigned long val; + u8 val; if (argc != 2) goto err; if (!strcasecmp(argv[0], "gc_percent")) { - if (kstrtoul(argv[1], 10, &val)) + if (kstrtou8(argv[1], 10, &val)) goto err; return pcache_cache_set_gc_percent(&pcache->cache, val); diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index d9ec783a37dd..9b66863991d1 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -258,7 +258,7 @@ out: static int mirror_flush(struct dm_target *ti) { struct mirror_set *ms = ti->private; - unsigned long error_bits; + unsigned long error_bits, unsup_bits; unsigned int i; struct dm_io_region io[MAX_NR_MIRRORS]; @@ -277,8 +277,8 @@ static int mirror_flush(struct dm_target *ti) } error_bits = -1; - dm_io(&io_req, ms->nr_mirrors, io, &error_bits, IOPRIO_DEFAULT); - if (unlikely(error_bits != 0)) { + dm_io(&io_req, ms->nr_mirrors, io, &error_bits, &unsup_bits, IOPRIO_DEFAULT); + if (unlikely((error_bits | unsup_bits) != 0)) { for (i = 0; i < ms->nr_mirrors; i++) if (test_bit(i, &error_bits)) fail_mirror(ms->mirror + i, @@ -511,7 +511,7 @@ static void hold_bio(struct mirror_set *ms, struct bio *bio) * Reads *--------------------------------------------------------------- */ -static void read_callback(unsigned long error, void *context) +static void read_callback(unsigned long error, unsigned long unsup, void *context) { struct bio *bio = context; struct mirror *m; @@ -520,6 +520,8 @@ static void read_callback(unsigned long error, void *context) bio_set_m(bio, NULL); if (likely(!error)) { + if (unlikely(unsup != 0)) + bio->bi_status = BLK_STS_INVAL; bio_endio(bio); return; } @@ -553,7 +555,7 @@ static void read_async_bio(struct mirror *m, struct bio *bio) map_region(&io, m, bio); bio_set_m(bio, m); - BUG_ON(dm_io(&io_req, 1, &io, NULL, IOPRIO_DEFAULT)); + BUG_ON(dm_io(&io_req, 1, &io, NULL, NULL, IOPRIO_DEFAULT)); } static inline int region_in_sync(struct mirror_set *ms, region_t region, @@ -600,7 +602,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads) * NOSYNC: increment pending, just write to the default mirror *--------------------------------------------------------------------- */ -static void write_callback(unsigned long error, void *context) +static void write_callback(unsigned long error, unsigned long unsup, void *context) { unsigned int i; struct bio *bio = context; @@ -617,7 +619,7 @@ static void write_callback(unsigned long error, void *context) * This way we handle both writes to SYNC and NOSYNC * regions with the same code. */ - if (likely(!error)) { + if (likely(!(error | unsup))) { bio_endio(bio); return; } @@ -632,6 +634,12 @@ static void write_callback(unsigned long error, void *context) return; } + if (!error && unsup) { + bio->bi_status = BLK_STS_INVAL; + bio_endio(bio); + return; + } + for (i = 0; i < ms->nr_mirrors; i++) if (test_bit(i, &error)) fail_mirror(ms->mirror + i, DM_RAID1_WRITE_ERROR); @@ -680,7 +688,7 @@ static void do_write(struct mirror_set *ms, struct bio *bio) */ bio_set_m(bio, get_default_mirror(ms)); - BUG_ON(dm_io(&io_req, ms->nr_mirrors, io, NULL, IOPRIO_DEFAULT)); + BUG_ON(dm_io(&io_req, ms->nr_mirrors, io, NULL, NULL, IOPRIO_DEFAULT)); } static void do_writes(struct mirror_set *ms, struct bio_list *writes) @@ -1262,7 +1270,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, return DM_ENDIO_DONE; } - if (*error == BLK_STS_NOTSUPP) + if (*error == BLK_STS_NOTSUPP || *error == BLK_STS_INVAL) goto out; if (bio->bi_opf & REQ_RAHEAD) diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 0e13d60bfdd1..0dc429eb2692 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -223,7 +223,7 @@ static void do_metadata(struct work_struct *work) { struct mdata_req *req = container_of(work, struct mdata_req, work); - req->result = dm_io(req->io_req, 1, req->where, NULL, IOPRIO_DEFAULT); + req->result = dm_io(req->io_req, 1, req->where, NULL, NULL, IOPRIO_DEFAULT); } /* @@ -247,7 +247,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, blk_opf_t opf, struct mdata_req req; if (!metadata) - return dm_io(&io_req, 1, &where, NULL, IOPRIO_DEFAULT); + return dm_io(&io_req, 1, &where, NULL, NULL, IOPRIO_DEFAULT); req.where = &where; req.io_req = &io_req; diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c index dbff4922e068..8019eeb4cc91 100644 --- a/drivers/md/dm-stats.c +++ b/drivers/md/dm-stats.c @@ -178,8 +178,10 @@ static void dm_stat_free(struct rcu_head *head) kfree(s->program_id); kfree(s->aux_data); for_each_possible_cpu(cpu) { - dm_kvfree(s->stat_percpu[cpu][0].histogram, s->histogram_alloc_size); - dm_kvfree(s->stat_percpu[cpu], s->percpu_alloc_size); + if (s->stat_percpu[cpu]) { + dm_kvfree(s->stat_percpu[cpu][0].histogram, s->histogram_alloc_size); + dm_kvfree(s->stat_percpu[cpu], s->percpu_alloc_size); + } } dm_kvfree(s->stat_shared[0].tmp.histogram, s->histogram_alloc_size); dm_kvfree(s, s->shared_alloc_size); diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c index 50a52ca50b34..65d169ffa753 100644 --- a/drivers/md/dm-switch.c +++ b/drivers/md/dm-switch.c @@ -184,7 +184,7 @@ static void switch_region_table_write(struct switch_ctx *sctx, unsigned long reg pte = sctx->region_table[region_index]; pte &= ~((((region_table_slot_t)1 << sctx->region_table_entry_bits) - 1) << bit); pte |= (region_table_slot_t)value << bit; - sctx->region_table[region_index] = pte; + WRITE_ONCE(sctx->region_table[region_index], pte); } /* diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index 40c0664fa034..2c754144e929 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -379,7 +379,7 @@ static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io, io_loc.bdev = v->data_dev->bdev; io_loc.sector = cur_block << (v->data_dev_block_bits - SECTOR_SHIFT); io_loc.count = 1 << (v->data_dev_block_bits - SECTOR_SHIFT); - r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + r = dm_io(&io_req, 1, &io_loc, NULL, NULL, IOPRIO_DEFAULT); if (unlikely(r)) goto free_ret; diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c index af54e289bceb..34148aa4df79 100644 --- a/drivers/md/dm-writecache.c +++ b/drivers/md/dm-writecache.c @@ -474,12 +474,14 @@ struct io_notify { atomic_t count; }; -static void writecache_notify_io(unsigned long error, void *context) +static void writecache_notify_io(unsigned long error, unsigned long unsup, void *context) { struct io_notify *endio = context; if (unlikely(error != 0)) writecache_error(endio->wc, -EIO, "error writing metadata"); + else if (unlikely(unsup != 0)) + writecache_error(endio->wc, -EOPNOTSUPP, "error writing metadata"); BUG_ON(atomic_read(&endio->count) <= 0); if (atomic_dec_and_test(&endio->count)) complete(&endio->c); @@ -530,11 +532,11 @@ static void ssd_commit_flushed(struct dm_writecache *wc, bool wait_for_ios) req.notify.context = &endio; /* writing via async dm-io (implied by notify.fn above) won't return an error */ - (void) dm_io(&req, 1, ®ion, NULL, IOPRIO_DEFAULT); + (void) dm_io(&req, 1, ®ion, NULL, NULL, IOPRIO_DEFAULT); i = j; } - writecache_notify_io(0, &endio); + writecache_notify_io(0, 0, &endio); wait_for_completion_io(&endio.c); if (wait_for_ios) @@ -567,7 +569,7 @@ static void ssd_commit_superblock(struct dm_writecache *wc) req.notify.fn = NULL; req.notify.context = NULL; - r = dm_io(&req, 1, ®ion, NULL, IOPRIO_DEFAULT); + r = dm_io(&req, 1, ®ion, NULL, NULL, IOPRIO_DEFAULT); if (unlikely(r)) writecache_error(wc, r, "error writing superblock"); } @@ -595,7 +597,7 @@ static void writecache_disk_flush(struct dm_writecache *wc, struct dm_dev *dev) req.client = wc->dm_io; req.notify.fn = NULL; - r = dm_io(&req, 1, ®ion, NULL, IOPRIO_DEFAULT); + r = dm_io(&req, 1, ®ion, NULL, NULL, IOPRIO_DEFAULT); if (unlikely(r)) writecache_error(wc, r, "error flushing metadata: %d", r); } @@ -989,7 +991,7 @@ static int writecache_read_metadata(struct dm_writecache *wc, sector_t n_sectors req.client = wc->dm_io; req.notify.fn = NULL; - return dm_io(&req, 1, ®ion, NULL, IOPRIO_DEFAULT); + return dm_io(&req, 1, ®ion, NULL, NULL, IOPRIO_DEFAULT); } static void writecache_resume(struct dm_target *ti) diff --git a/drivers/md/md.c b/drivers/md/md.c index 0d60c211e7c0..5304e920dbcc 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1917,6 +1917,13 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_ rdev->bb_page, REQ_OP_READ, true)) return -EIO; bbp = (__le64 *)page_address(rdev->bb_page); + + /* check for badblocks api. */ + if (sb->bblog_shift >= BITS_PER_TYPE(sector_t)) { + pr_err("md: %pg: bogus bblog_shift %u for badblocks.\n", + rdev->bdev, sb->bblog_shift); + return -EINVAL; + } rdev->badblocks.shift = sb->bblog_shift; for (i = 0 ; i < (sectors << (9-3)) ; i++, bbp++) { u64 bb = le64_to_cpu(*bbp); diff --git a/drivers/md/persistent-data/dm-array.c b/drivers/md/persistent-data/dm-array.c index 8f8792e55806..961fa3c1439a 100644 --- a/drivers/md/persistent-data/dm-array.c +++ b/drivers/md/persistent-data/dm-array.c @@ -38,6 +38,14 @@ struct array_block { */ #define CSUM_XOR 595846735 +/* + * Each array block can hold this many values. + */ +static uint32_t calc_max_entries(size_t value_size, size_t size_of_block) +{ + return (size_of_block - sizeof(struct array_block)) / value_size; +} + static void array_block_prepare_for_write(const struct dm_block_validator *v, struct dm_block *b, size_t size_of_block) @@ -55,6 +63,7 @@ static int array_block_check(const struct dm_block_validator *v, size_t size_of_block) { struct array_block *bh_le = dm_block_data(b); + uint32_t nr_entries, max_entries, value_size; __le32 csum_disk; if (dm_block_location(b) != le64_to_cpu(bh_le->blocknr)) { @@ -74,6 +83,26 @@ static int array_block_check(const struct dm_block_validator *v, return -EILSEQ; } + nr_entries = le32_to_cpu(bh_le->nr_entries); + max_entries = le32_to_cpu(bh_le->max_entries); + value_size = le32_to_cpu(bh_le->value_size); + + if (!value_size) { + DMERR_LIMIT("%s failed: value_size is zero", __func__); + return -EILSEQ; + } + + if (max_entries != calc_max_entries(value_size, size_of_block)) { + DMERR_LIMIT("%s failed: max_entries %u invalid for value_size %u", + __func__, max_entries, value_size); + return -EILSEQ; + } + + if (nr_entries > max_entries) { + DMERR_LIMIT("%s failed: too many entries", __func__); + return -EILSEQ; + } + return 0; } @@ -139,14 +168,6 @@ static void dec_ablock_entries(struct dm_array_info *info, struct array_block *a } /* - * Each array block can hold this many values. - */ -static uint32_t calc_max_entries(size_t value_size, size_t size_of_block) -{ - return (size_of_block - sizeof(struct array_block)) / value_size; -} - -/* * Allocate a new array block. The caller will need to unlock block. */ static int alloc_ablock(struct dm_array_info *info, size_t size_of_block, @@ -225,6 +246,14 @@ static int get_ablock(struct dm_array_info *info, dm_block_t b, return r; *ab = dm_block_data(*block); + if (le32_to_cpu((*ab)->value_size) != info->value_type.size) { + DMERR_LIMIT("%s failed: value_size %u != wanted %u", __func__, + le32_to_cpu((*ab)->value_size), + info->value_type.size); + dm_tm_unlock(info->btree_info.tm, *block); + return -EILSEQ; + } + return 0; } @@ -287,6 +316,14 @@ static int __shadow_ablock(struct dm_array_info *info, dm_block_t b, return r; *ab = dm_block_data(*block); + if (le32_to_cpu((*ab)->value_size) != info->value_type.size) { + DMERR_LIMIT("%s failed: value_size %u != wanted %u", __func__, + le32_to_cpu((*ab)->value_size), + info->value_type.size); + dm_tm_unlock(info->btree_info.tm, *block); + return -EILSEQ; + } + if (inc) inc_ablock_entries(info, *ab); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index d6b174454b1a..1ae9a587a959 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3384,7 +3384,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, struct md_rdev *rdev = conf->mirrors[j].rdev; if (rdev == NULL || test_bit(Faulty, &rdev->flags)) { - still_degraded = false; + still_degraded = true; break; } } |
