mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
[MTD] [NOR] fix cfi_cmdset_0001 FL_SYNCING race (take 2)
The patch fixes CFI issue with multipartitional devices leading to the set of errors or even deadlock. The problem is CFI FL_SYNCING state race with flash operations (e.g. erase suspend). It is reproduced by running intensive writes on one JFFS2 partition and simultaneously performing mount/unmount cycle on another partition of the same chip. Signed-off-by: Alexander Belyakov <abelyako@googlemail.com> Acked-by: Nicolas Pitre <nico@cam.org> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
parent
ef89a88013
commit
3afe7eb37f
1 changed files with 15 additions and 2 deletions
|
@ -725,6 +725,10 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
|
|||
struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
|
||||
unsigned long timeo = jiffies + HZ;
|
||||
|
||||
/* Prevent setting state FL_SYNCING for chip in suspended state. */
|
||||
if (mode == FL_SYNCING && chip->oldstate != FL_READY)
|
||||
goto sleep;
|
||||
|
||||
switch (chip->state) {
|
||||
|
||||
case FL_STATUS:
|
||||
|
@ -830,8 +834,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
|
|||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
retry:
|
||||
if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
|
||||
|| mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
|
||||
if (chip->priv &&
|
||||
(mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE
|
||||
|| mode == FL_SHUTDOWN) && chip->state != FL_SYNCING) {
|
||||
/*
|
||||
* OK. We have possibility for contention on the write/erase
|
||||
* operations which are global to the real chip and not per
|
||||
|
@ -881,6 +886,14 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
|
|||
return ret;
|
||||
}
|
||||
spin_lock(&shared->lock);
|
||||
|
||||
/* We should not own chip if it is already
|
||||
* in FL_SYNCING state. Put contender and retry. */
|
||||
if (chip->state == FL_SYNCING) {
|
||||
put_chip(map, contender, contender->start);
|
||||
spin_unlock(contender->mutex);
|
||||
goto retry;
|
||||
}
|
||||
spin_unlock(contender->mutex);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue