Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: lapb: Make "lapb_t1timer_running" able to detect an already running timer

Problem:

The "lapb_t1timer_running" function in "lapb_timer.c" is used in only
one place: in the "lapb_kick" function in "lapb_out.c". "lapb_kick" calls
"lapb_t1timer_running" to check if the timer is already pending, and if
it is not, schedule it to run.

However, if the timer has already fired and is running, and is waiting to
get the "lapb->lock" lock, "lapb_t1timer_running" will not detect this,
and "lapb_kick" will then schedule a new timer. The old timer will then
abort when it sees a new timer pending.

I think this is not right. The purpose of "lapb_kick" should be ensuring
that the actual work of the timer function is scheduled to be done.
If the timer function is already running but waiting for the lock,
"lapb_kick" should not abort and reschedule it.

Changes made:

I added a new field "t1timer_running" in "struct lapb_cb" for
"lapb_t1timer_running" to use. "t1timer_running" will accurately reflect
whether the actual work of the timer is pending. If the timer has fired
but is still waiting for the lock, "t1timer_running" will still correctly
reflect whether the actual work is waiting to be done.

The old "t1timer_stop" field, whose only responsibility is to ask a timer
(that is already running but waiting for the lock) to abort, is no longer
needed, because the new "t1timer_running" field can fully take over its
responsibility. Therefore "t1timer_stop" is deleted.

"t1timer_running" is not simply a negation of the old "t1timer_stop".
At the end of the timer function, if it does not reschedule itself,
"t1timer_running" is set to false to indicate that the timer is stopped.

For consistency of the code, I also added "t2timer_running" and deleted
"t2timer_stop".

Signed-off-by: Xie He <xie.he.0141@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Xie He and committed by
David S. Miller
65d2dbb3 1ab568e9

+15 -10
+1 -1
include/net/lapb.h
··· 92 92 unsigned short n2, n2count; 93 93 unsigned short t1, t2; 94 94 struct timer_list t1timer, t2timer; 95 - bool t1timer_stop, t2timer_stop; 95 + bool t1timer_running, t2timer_running; 96 96 97 97 /* Internal control information */ 98 98 struct sk_buff_head write_queue;
+2 -2
net/lapb/lapb_iface.c
··· 122 122 123 123 timer_setup(&lapb->t1timer, NULL, 0); 124 124 timer_setup(&lapb->t2timer, NULL, 0); 125 - lapb->t1timer_stop = true; 126 - lapb->t2timer_stop = true; 125 + lapb->t1timer_running = false; 126 + lapb->t2timer_running = false; 127 127 128 128 lapb->t1 = LAPB_DEFAULT_T1; 129 129 lapb->t2 = LAPB_DEFAULT_T2;
+12 -7
net/lapb/lapb_timer.c
··· 40 40 lapb->t1timer.function = lapb_t1timer_expiry; 41 41 lapb->t1timer.expires = jiffies + lapb->t1; 42 42 43 - lapb->t1timer_stop = false; 43 + lapb->t1timer_running = true; 44 44 add_timer(&lapb->t1timer); 45 45 } 46 46 ··· 51 51 lapb->t2timer.function = lapb_t2timer_expiry; 52 52 lapb->t2timer.expires = jiffies + lapb->t2; 53 53 54 - lapb->t2timer_stop = false; 54 + lapb->t2timer_running = true; 55 55 add_timer(&lapb->t2timer); 56 56 } 57 57 58 58 void lapb_stop_t1timer(struct lapb_cb *lapb) 59 59 { 60 - lapb->t1timer_stop = true; 60 + lapb->t1timer_running = false; 61 61 del_timer(&lapb->t1timer); 62 62 } 63 63 64 64 void lapb_stop_t2timer(struct lapb_cb *lapb) 65 65 { 66 - lapb->t2timer_stop = true; 66 + lapb->t2timer_running = false; 67 67 del_timer(&lapb->t2timer); 68 68 } 69 69 70 70 int lapb_t1timer_running(struct lapb_cb *lapb) 71 71 { 72 - return timer_pending(&lapb->t1timer); 72 + return lapb->t1timer_running; 73 73 } 74 74 75 75 static void lapb_t2timer_expiry(struct timer_list *t) ··· 79 79 spin_lock_bh(&lapb->lock); 80 80 if (timer_pending(&lapb->t2timer)) /* A new timer has been set up */ 81 81 goto out; 82 - if (lapb->t2timer_stop) /* The timer has been stopped */ 82 + if (!lapb->t2timer_running) /* The timer has been stopped */ 83 83 goto out; 84 84 85 85 if (lapb->condition & LAPB_ACK_PENDING_CONDITION) { 86 86 lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; 87 87 lapb_timeout_response(lapb); 88 88 } 89 + lapb->t2timer_running = false; 89 90 90 91 out: 91 92 spin_unlock_bh(&lapb->lock); ··· 99 98 spin_lock_bh(&lapb->lock); 100 99 if (timer_pending(&lapb->t1timer)) /* A new timer has been set up */ 101 100 goto out; 102 - if (lapb->t1timer_stop) /* The timer has been stopped */ 101 + if (!lapb->t1timer_running) /* The timer has been stopped */ 103 102 goto out; 104 103 105 104 switch (lapb->state) { ··· 128 127 lapb->state = LAPB_STATE_0; 129 128 lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); 130 129 lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev); 130 + lapb->t1timer_running = false; 131 131 goto out; 132 132 } else { 133 133 lapb->n2count++; ··· 153 151 lapb->state = LAPB_STATE_0; 154 152 lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT); 155 153 lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev); 154 + lapb->t1timer_running = false; 156 155 goto out; 157 156 } else { 158 157 lapb->n2count++; ··· 172 169 lapb_stop_t2timer(lapb); 173 170 lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); 174 171 lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev); 172 + lapb->t1timer_running = false; 175 173 goto out; 176 174 } else { 177 175 lapb->n2count++; ··· 190 186 lapb->state = LAPB_STATE_0; 191 187 lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); 192 188 lapb_dbg(0, "(%p) S4 -> S0\n", lapb->dev); 189 + lapb->t1timer_running = false; 193 190 goto out; 194 191 } else { 195 192 lapb->n2count++;