From 645d40952c5a6cf916f9dc566cf07ae5348f64c7 Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Thu, 10 May 2018 11:06:37 +0800 Subject: block: add verifier for cmdline partition I meet strange filesystem corruption issue recently, the reason is there are overlaps partitions in cmdline partition argument. This patch add verifier for cmdline partition, then if there are overlaps partitions, cmdline_partition will log a warning. We don't treat overlaps partition as a error: " Caizhiyong said: Partition overlap was intentionally designed in this cmdline partition. reference http://lists.infradead.org/pipermail/linux-mtd/2013-August/048092.html " Signed-off-by: Wang YanQing Signed-off-by: Jens Axboe --- block/partitions/cmdline.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'block') diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c index e333583ab38c..60fb3df9897c 100644 --- a/block/partitions/cmdline.c +++ b/block/partitions/cmdline.c @@ -58,6 +58,62 @@ static int __init cmdline_parts_setup(char *s) } __setup("blkdevparts=", cmdline_parts_setup); +static bool has_overlaps(sector_t from, sector_t size, + sector_t from2, sector_t size2) +{ + sector_t end = from + size; + sector_t end2 = from2 + size2; + + if (from >= from2 && from < end2) + return true; + + if (end > from2 && end <= end2) + return true; + + if (from2 >= from && from2 < end) + return true; + + if (end2 > from && end2 <= end) + return true; + + return false; +} + +static inline void overlaps_warns_header(void) +{ + pr_warn("Overlapping partitions are used in command line partitions."); + pr_warn("Don't use filesystems on overlapping partitions:"); +} + +static void cmdline_parts_verifier(int slot, struct parsed_partitions *state) +{ + int i; + bool header = true; + + for (; slot < state->limit && state->parts[slot].has_info; slot++) { + for (i = slot+1; i < state->limit && state->parts[i].has_info; + i++) { + if (has_overlaps(state->parts[slot].from, + state->parts[slot].size, + state->parts[i].from, + state->parts[i].size)) { + if (header) { + header = false; + overlaps_warns_header(); + } + pr_warn("%s[%llu,%llu] overlaps with " + "%s[%llu,%llu].", + state->parts[slot].info.volname, + (u64)state->parts[slot].from << 9, + (u64)state->parts[slot].size << 9, + state->parts[i].info.volname, + (u64)state->parts[i].from << 9, + (u64)state->parts[i].size << 9); + } + } + } +} + /* * Purpose: allocate cmdline partitions. * Returns: @@ -93,6 +149,7 @@ int cmdline_partition(struct parsed_partitions *state) disk_size = get_capacity(state->bdev->bd_disk) << 9; cmdline_parts_set(parts, disk_size, 1, add_part, (void *)state); + cmdline_parts_verifier(1, state); strlcat(state->pp_buf, "\n", PAGE_SIZE); -- cgit v1.2.3 From 84fca1b0c461e741268fe947f641296c0d963a56 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 6 Jun 2018 16:21:40 +0200 Subject: block: pass failfast and driver-specific flags to flush requests If flush requests are being sent to the device we need to inherit the failfast and driver-specific flags, too, otherwise I/O will fail. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/blk-flush.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'block') diff --git a/block/blk-flush.c b/block/blk-flush.c index f17170675917..058abdb50f31 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -94,7 +94,7 @@ enum { }; static bool blk_kick_flush(struct request_queue *q, - struct blk_flush_queue *fq); + struct blk_flush_queue *fq, unsigned int flags); static unsigned int blk_flush_policy(unsigned long fflags, struct request *rq) { @@ -212,7 +212,7 @@ static bool blk_flush_complete_seq(struct request *rq, BUG(); } - kicked = blk_kick_flush(q, fq); + kicked = blk_kick_flush(q, fq, rq->cmd_flags); return kicked | queued; } @@ -281,6 +281,7 @@ static void flush_end_io(struct request *flush_rq, blk_status_t error) * blk_kick_flush - consider issuing flush request * @q: request_queue being kicked * @fq: flush queue + * @flags: cmd_flags of the original request * * Flush related states of @q have changed, consider issuing flush request. * Please read the comment at the top of this file for more info. @@ -291,7 +292,8 @@ static void flush_end_io(struct request *flush_rq, blk_status_t error) * RETURNS: * %true if flush was issued, %false otherwise. */ -static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq) +static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq, + unsigned int flags) { struct list_head *pending = &fq->flush_queue[fq->flush_pending_idx]; struct request *first_rq = @@ -346,6 +348,7 @@ static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq) } flush_rq->cmd_flags = REQ_OP_FLUSH | REQ_PREFLUSH; + flush_rq->cmd_flags |= (flags & REQ_DRV) | (flags & REQ_FAILFAST_MASK); flush_rq->rq_flags |= RQF_FLUSH_SEQ; flush_rq->rq_disk = first_rq->rq_disk; flush_rq->end_io = flush_end_io; -- cgit v1.2.3 From c04fa44b76b8d9d4f6b577030aa0cbb20359c428 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 7 Jun 2018 10:29:44 +0200 Subject: block: always set partition number to '0' in blk_partition_remap() blk_partition_remap() will only clear bi_partno if an actual remapping has happened. But flush request et al don't have an actual size, so the remapping doesn't happen and bi_partno is never cleared. So for stacked devices blk_partition_remap() will be called on each level. If (as is the case for native nvme multipathing) one of the lower-level devices do _not_support partitioning a spurious I/O error is generated. Reviewed-by: Johannes Thumshirn Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/blk-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'block') diff --git a/block/blk-core.c b/block/blk-core.c index 3f56be15f17e..cf0ee764b908 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2220,10 +2220,10 @@ static inline int blk_partition_remap(struct bio *bio) if (bio_check_eod(bio, part_nr_sects_read(p))) goto out; bio->bi_iter.bi_sector += p->start_sect; - bio->bi_partno = 0; trace_block_bio_remap(bio->bi_disk->queue, bio, part_devt(p), bio->bi_iter.bi_sector - p->start_sect); } + bio->bi_partno = 0; ret = 0; out: rcu_read_unlock(); -- cgit v1.2.3 From 28e89fd914a22e8a64f05ae2f0048b06165f371b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 7 Jun 2018 14:42:05 -0600 Subject: block: add bioset_init_from_src() helper Add a helper that allows a caller to initialize a new bio_set, using the settings from an existing bio_set. Reported-by: Venkat R.B Tested-by: Venkat R.B Tested-by: Li Wang Reviewed-by: Mike Snitzer Signed-off-by: Jens Axboe --- block/bio.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'block') diff --git a/block/bio.c b/block/bio.c index 595663e0281a..bf516d873ce9 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1967,6 +1967,24 @@ bad: } EXPORT_SYMBOL(bioset_init); +/* + * Initialize and setup a new bio_set, based on the settings from + * another bio_set. + */ +int bioset_init_from_src(struct bio_set *bs, struct bio_set *src) +{ + int flags; + + flags = 0; + if (src->bvec_pool.min_nr) + flags |= BIOSET_NEED_BVECS; + if (src->rescue_workqueue) + flags |= BIOSET_NEED_RESCUER; + + return bioset_init(bs, src->bio_pool.min_nr, src->front_pad, flags); +} +EXPORT_SYMBOL(bioset_init_from_src); + #ifdef CONFIG_BLK_CGROUP /** -- cgit v1.2.3