Skip to content

Commit a390d1f

Browse files
mslusarzdavem330
authored andcommitted
phylib: convert state_queue work to delayed_work
It closes a race in phy_stop_machine when reprogramming of phy_timer (from phy_state_machine) happens between del_timer_sync and cancel_work_sync. Without this change it could lead to crash if phy_device would be freed after phy_stop_machine (timer would fire and schedule freed work). Signed-off-by: Marcin Slusarz <[email protected]> Acked-by: Jean Delvare <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 34cd347 commit a390d1f

File tree

2 files changed

+12
-32
lines changed

2 files changed

+12
-32
lines changed

drivers/net/phy/phy.c

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,6 @@ EXPORT_SYMBOL(phy_start_aneg);
414414

415415
static void phy_change(struct work_struct *work);
416416
static void phy_state_machine(struct work_struct *work);
417-
static void phy_timer(unsigned long data);
418417

419418
/**
420419
* phy_start_machine - start PHY state machine tracking
@@ -434,11 +433,8 @@ void phy_start_machine(struct phy_device *phydev,
434433
{
435434
phydev->adjust_state = handler;
436435

437-
INIT_WORK(&phydev->state_queue, phy_state_machine);
438-
init_timer(&phydev->phy_timer);
439-
phydev->phy_timer.function = &phy_timer;
440-
phydev->phy_timer.data = (unsigned long) phydev;
441-
mod_timer(&phydev->phy_timer, jiffies + HZ);
436+
INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine);
437+
schedule_delayed_work(&phydev->state_queue, jiffies + HZ);
442438
}
443439

444440
/**
@@ -451,8 +447,7 @@ void phy_start_machine(struct phy_device *phydev,
451447
*/
452448
void phy_stop_machine(struct phy_device *phydev)
453449
{
454-
del_timer_sync(&phydev->phy_timer);
455-
cancel_work_sync(&phydev->state_queue);
450+
cancel_delayed_work_sync(&phydev->state_queue);
456451

457452
mutex_lock(&phydev->lock);
458453
if (phydev->state > PHY_UP)
@@ -680,11 +675,9 @@ static void phy_change(struct work_struct *work)
680675
if (err)
681676
goto irq_enable_err;
682677

683-
/* Stop timer and run the state queue now. The work function for
684-
* state_queue will start the timer up again.
685-
*/
686-
del_timer(&phydev->phy_timer);
687-
schedule_work(&phydev->state_queue);
678+
/* reschedule state queue work to run as soon as possible */
679+
cancel_delayed_work_sync(&phydev->state_queue);
680+
schedule_delayed_work(&phydev->state_queue, 0);
688681

689682
return;
690683

@@ -761,14 +754,13 @@ EXPORT_SYMBOL(phy_start);
761754
/**
762755
* phy_state_machine - Handle the state machine
763756
* @work: work_struct that describes the work to be done
764-
*
765-
* Description: Scheduled by the state_queue workqueue each time
766-
* phy_timer is triggered.
767757
*/
768758
static void phy_state_machine(struct work_struct *work)
769759
{
760+
struct delayed_work *dwork =
761+
container_of(work, struct delayed_work, work);
770762
struct phy_device *phydev =
771-
container_of(work, struct phy_device, state_queue);
763+
container_of(dwork, struct phy_device, state_queue);
772764
int needs_aneg = 0;
773765
int err = 0;
774766

@@ -946,17 +938,6 @@ static void phy_state_machine(struct work_struct *work)
946938
if (err < 0)
947939
phy_error(phydev);
948940

949-
mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ);
950-
}
951-
952-
/* PHY timer which schedules the state machine work */
953-
static void phy_timer(unsigned long data)
954-
{
955-
struct phy_device *phydev = (struct phy_device *)data;
956-
957-
/*
958-
* PHY I/O operations can potentially sleep so we ensure that
959-
* it's done from a process context
960-
*/
961-
schedule_work(&phydev->state_queue);
941+
schedule_delayed_work(&phydev->state_queue,
942+
jiffies + PHY_STATE_TIME * HZ);
962943
}

include/linux/phy.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,7 @@ struct phy_device {
315315

316316
/* Interrupt and Polling infrastructure */
317317
struct work_struct phy_queue;
318-
struct work_struct state_queue;
319-
struct timer_list phy_timer;
318+
struct delayed_work state_queue;
320319
atomic_t irq_disable;
321320

322321
struct mutex lock;

0 commit comments

Comments
 (0)