forked from Minki/linux
bonding: Fix jiffies overflow problems (again)
The time_before_eq()/time_after_eq() functions operate on unsigned long and only work if the difference between the two compared values is smaller than half the range of unsigned long (31 bits on i386). Some of the variables (slave->jiffies, dev->trans_start, dev->last_rx) used by bonding store a copy of jiffies and may not be updated for a long time. With HZ=1000, time_before_eq()/time_after_eq() will start giving bad results after ~25 days. jiffies will never be before slave->jiffies, dev->trans_start, dev->last_rx by more than possibly a couple ticks caused by preemption of this code. This allows us to detect/prevent these overflows by replacing time_before_eq()/time_after_eq() with time_in_range(). Signed-off-by: Jiri Bohac <jbohac@suse.cz> Signed-off-by: Jean Delvare <jdelvare@suse.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c4433be6e1
commit
cb32f2a0d1
@ -2797,9 +2797,15 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
|
||||
* so it can wait
|
||||
*/
|
||||
bond_for_each_slave(bond, slave, i) {
|
||||
unsigned long trans_start = dev_trans_start(slave->dev);
|
||||
|
||||
if (slave->link != BOND_LINK_UP) {
|
||||
if (time_before_eq(jiffies, dev_trans_start(slave->dev) + delta_in_ticks) &&
|
||||
time_before_eq(jiffies, slave->dev->last_rx + delta_in_ticks)) {
|
||||
if (time_in_range(jiffies,
|
||||
trans_start - delta_in_ticks,
|
||||
trans_start + delta_in_ticks) &&
|
||||
time_in_range(jiffies,
|
||||
slave->dev->last_rx - delta_in_ticks,
|
||||
slave->dev->last_rx + delta_in_ticks)) {
|
||||
|
||||
slave->link = BOND_LINK_UP;
|
||||
slave->state = BOND_STATE_ACTIVE;
|
||||
@ -2827,8 +2833,12 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
|
||||
* when the source ip is 0, so don't take the link down
|
||||
* if we don't know our ip yet
|
||||
*/
|
||||
if (time_after_eq(jiffies, dev_trans_start(slave->dev) + 2*delta_in_ticks) ||
|
||||
(time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) {
|
||||
if (!time_in_range(jiffies,
|
||||
trans_start - delta_in_ticks,
|
||||
trans_start + 2 * delta_in_ticks) ||
|
||||
!time_in_range(jiffies,
|
||||
slave->dev->last_rx - delta_in_ticks,
|
||||
slave->dev->last_rx + 2 * delta_in_ticks)) {
|
||||
|
||||
slave->link = BOND_LINK_DOWN;
|
||||
slave->state = BOND_STATE_BACKUP;
|
||||
@ -2883,13 +2893,16 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
|
||||
{
|
||||
struct slave *slave;
|
||||
int i, commit = 0;
|
||||
unsigned long trans_start;
|
||||
|
||||
bond_for_each_slave(bond, slave, i) {
|
||||
slave->new_link = BOND_LINK_NOCHANGE;
|
||||
|
||||
if (slave->link != BOND_LINK_UP) {
|
||||
if (time_before_eq(jiffies, slave_last_rx(bond, slave) +
|
||||
delta_in_ticks)) {
|
||||
if (time_in_range(jiffies,
|
||||
slave_last_rx(bond, slave) - delta_in_ticks,
|
||||
slave_last_rx(bond, slave) + delta_in_ticks)) {
|
||||
|
||||
slave->new_link = BOND_LINK_UP;
|
||||
commit++;
|
||||
}
|
||||
@ -2902,8 +2915,9 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
|
||||
* active. This avoids bouncing, as the last receive
|
||||
* times need a full ARP monitor cycle to be updated.
|
||||
*/
|
||||
if (!time_after_eq(jiffies, slave->jiffies +
|
||||
2 * delta_in_ticks))
|
||||
if (time_in_range(jiffies,
|
||||
slave->jiffies - delta_in_ticks,
|
||||
slave->jiffies + 2 * delta_in_ticks))
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -2921,8 +2935,10 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
|
||||
*/
|
||||
if (slave->state == BOND_STATE_BACKUP &&
|
||||
!bond->current_arp_slave &&
|
||||
time_after(jiffies, slave_last_rx(bond, slave) +
|
||||
3 * delta_in_ticks)) {
|
||||
!time_in_range(jiffies,
|
||||
slave_last_rx(bond, slave) - delta_in_ticks,
|
||||
slave_last_rx(bond, slave) + 3 * delta_in_ticks)) {
|
||||
|
||||
slave->new_link = BOND_LINK_DOWN;
|
||||
commit++;
|
||||
}
|
||||
@ -2933,11 +2949,15 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
|
||||
* - (more than 2*delta since receive AND
|
||||
* the bond has an IP address)
|
||||
*/
|
||||
trans_start = dev_trans_start(slave->dev);
|
||||
if ((slave->state == BOND_STATE_ACTIVE) &&
|
||||
(time_after_eq(jiffies, dev_trans_start(slave->dev) +
|
||||
2 * delta_in_ticks) ||
|
||||
(time_after_eq(jiffies, slave_last_rx(bond, slave)
|
||||
+ 2 * delta_in_ticks)))) {
|
||||
(!time_in_range(jiffies,
|
||||
trans_start - delta_in_ticks,
|
||||
trans_start + 2 * delta_in_ticks) ||
|
||||
!time_in_range(jiffies,
|
||||
slave_last_rx(bond, slave) - delta_in_ticks,
|
||||
slave_last_rx(bond, slave) + 2 * delta_in_ticks))) {
|
||||
|
||||
slave->new_link = BOND_LINK_DOWN;
|
||||
commit++;
|
||||
}
|
||||
@ -2956,6 +2976,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
|
||||
{
|
||||
struct slave *slave;
|
||||
int i;
|
||||
unsigned long trans_start;
|
||||
|
||||
bond_for_each_slave(bond, slave, i) {
|
||||
switch (slave->new_link) {
|
||||
@ -2963,10 +2984,11 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
|
||||
continue;
|
||||
|
||||
case BOND_LINK_UP:
|
||||
trans_start = dev_trans_start(slave->dev);
|
||||
if ((!bond->curr_active_slave &&
|
||||
time_before_eq(jiffies,
|
||||
dev_trans_start(slave->dev) +
|
||||
delta_in_ticks)) ||
|
||||
time_in_range(jiffies,
|
||||
trans_start - delta_in_ticks,
|
||||
trans_start + delta_in_ticks)) ||
|
||||
bond->curr_active_slave != slave) {
|
||||
slave->link = BOND_LINK_UP;
|
||||
bond->current_arp_slave = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user