mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 10:00:53 +07:00
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;
|
sleep_time = chip_op_time / 2;
|
||||||
|
|
||||||
for (;;) {
|
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);
|
status = map_read(map, cmd_adr);
|
||||||
if (map_word_andequal(map, status, status_OK, status_OK))
|
if (map_word_andequal(map, status, status_OK, status_OK))
|
||||||
break;
|
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) {
|
if (!timeo) {
|
||||||
map_write(map, CMD(0x70), cmd_adr);
|
map_write(map, CMD(0x70), cmd_adr);
|
||||||
chip->state = FL_STATUS;
|
chip->state = FL_STATUS;
|
||||||
@ -1257,27 +1279,6 @@ static int inval_cache_and_wait_for_operation(
|
|||||||
timeo--;
|
timeo--;
|
||||||
}
|
}
|
||||||
mutex_lock(&chip->mutex);
|
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. */
|
/* Done and happy. */
|
||||||
|
Loading…
Reference in New Issue
Block a user