On Mon, Dec 14, 2020 at 1:49 PM Song Liu <songliubraving@xxxxxx> wrote: > > Here is the root cause of this issue. > > We miss a cast to sector_t in raid5_run(). The fix is: > > diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c > index 39343479ac2a9..ca0b29ac9d9a8 100644 > --- a/drivers/md/raid5.c > +++ b/drivers/md/raid5.c > @@ -7662,7 +7662,7 @@ static int raid5_run(struct mddev *mddev) > } > > /* device size must be a multiple of chunk size */ > - mddev->dev_sectors &= ~(mddev->chunk_sectors - 1); > + mddev->dev_sectors &= ~((sector_t)mddev->chunk_sectors - 1); > mddev->resync_max_sectors = mddev->dev_sectors; > > if (mddev->degraded > dirty_parity_disks && Ok, so this made me go "Hmm, this might be a pattern to look out for". It's zero-extending a binary 'not', which means that the 'not' only did low bits, and the zero-extended bits weren't set. That is probably fine in many situations, but it also does smell like a problem case. It's one reason why the kernel uses signed types for some fundamental constants - look at PAGE_SIZE for example. Exactly because ~(PAGE_SIZE-1) needs to set all the high bits. Anyway, since I have nothing better to do during the merge window (hah!) I tried to see if I can come up with a sparse check for this situation. Here is my very quick hack to sparse, which I'm just throwing over the fence to Luc and others to look at (because I still have a _lot_ of pulls to go through), but it does actually flag the problem in 5.10: drivers/md/raid5.c:7665:56: warning: zero-extending a negation - upper bits not negated although I'm not entirely sure this won't cause way too many other warnings for things that are very valid. So it looks like the warning will be too noisy to be actually useful. But because it _does_ flag that thing, and because I'm too busy to see if it might be useful with some more work, I'll just post it here and see if somebody wants to play with it. Linus
linearize.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/linearize.c b/linearize.c index 0250c6bb..b1a18219 100644 --- a/linearize.c +++ b/linearize.c @@ -2520,6 +2520,25 @@ static void check_tainted_insn(struct instruction *insn) } } +static void check_zero_extend(struct instruction *insn) +{ + struct instruction *def; + pseudo_t src = insn->src1; + + if (src->type != PSEUDO_REG) + return; + def = src->def; + if (!def) + return; + switch (def->opcode) { + case OP_NEG: case OP_NOT: + warning(insn->pos, "zero-extending a negation - upper bits not negated"); + break; + default: + break; + } +} + /// // issue warnings after all possible DCE static void late_warnings(struct entrypoint *ep) @@ -2537,6 +2556,10 @@ static void late_warnings(struct entrypoint *ep) // Check for illegal offsets. check_access(insn); break; + case OP_ZEXT: + // Check for missing sign extension.. + check_zero_extend(insn); + break; } } END_FOR_EACH_PTR(insn); } END_FOR_EACH_PTR(bb);