mirror of https://gitee.com/openkylin/linux.git
mtd: fix race in cfi_cmdset_0001 driver
As inval_cache_and_wait_for_operation() drop and reclaim the lock to invalidate the cache, some other thread may suspend the operation before reaching the for(;;) loop. Therefore the loop must start with checking the chip->state before reading status from the chip. Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se> Acked-by: Michael Cashwell <mboards@prograde.net> Acked-by: Stefan Bigler <stefan.bigler@keymile.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Cc: stable@kernel.org
This commit is contained in:
parent
ceabebb2bd
commit
ecf3fde07c
|
@ -1230,10 +1230,32 @@ static int inval_cache_and_wait_for_operation(
|
|||
sleep_time = chip_op_time / 2;
|
||||
|
||||
for (;;) {
|
||||
if (chip->state != chip_state) {
|
||||
/* Someone's suspended the operation: sleep */
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&chip->wq, &wait);
|
||||
mutex_unlock(&chip->mutex);
|
||||
schedule();
|
||||
remove_wait_queue(&chip->wq, &wait);
|
||||
mutex_lock(&chip->mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
status = map_read(map, cmd_adr);
|
||||
if (map_word_andequal(map, status, status_OK, status_OK))
|
||||
break;
|
||||
|
||||
if (chip->erase_suspended && chip_state == FL_ERASING) {
|
||||
/* Erase suspend occured while sleep: reset timeout */
|
||||
timeo = reset_timeo;
|
||||
chip->erase_suspended = 0;
|
||||
}
|
||||
if (chip->write_suspended && chip_state == FL_WRITING) {
|
||||
/* Write suspend occured while sleep: reset timeout */
|
||||
timeo = reset_timeo;
|
||||
chip->write_suspended = 0;
|
||||
}
|
||||
if (!timeo) {
|
||||
map_write(map, CMD(0x70), cmd_adr);
|
||||
chip->state = FL_STATUS;
|
||||
|
@ -1257,27 +1279,6 @@ static int inval_cache_and_wait_for_operation(
|
|||
timeo--;
|
||||
}
|
||||
mutex_lock(&chip->mutex);
|
||||
|
||||
while (chip->state != chip_state) {
|
||||
/* Someone's suspended the operation: sleep */
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&chip->wq, &wait);
|
||||
mutex_unlock(&chip->mutex);
|
||||
schedule();
|
||||
remove_wait_queue(&chip->wq, &wait);
|
||||
mutex_lock(&chip->mutex);
|
||||
}
|
||||
if (chip->erase_suspended && chip_state == FL_ERASING) {
|
||||
/* Erase suspend occured while sleep: reset timeout */
|
||||
timeo = reset_timeo;
|
||||
chip->erase_suspended = 0;
|
||||
}
|
||||
if (chip->write_suspended && chip_state == FL_WRITING) {
|
||||
/* Write suspend occured while sleep: reset timeout */
|
||||
timeo = reset_timeo;
|
||||
chip->write_suspended = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Done and happy. */
|
||||
|
|
Loading…
Reference in New Issue