Skip to content

Commit c362a06

Browse files
dcarattidavem330
authored andcommitted
net/sched: act_gate: fix configuration of the periodic timer
assigning a dummy value of 'clock_id' to avoid cancellation of the cycle timer before its initialization was a temporary solution, and we still need to handle the case where act_gate timer parameters are changed by commands like the following one: # tc action replace action gate <parameters> the fix consists in the following items: 1) remove the workaround assignment of 'clock_id', and init the list of entries before the first error path after IDR atomic check/allocation 2) validate 'clock_id' earlier: there is no need to do IDR atomic check/allocation if we know that 'clock_id' is a bad value 3) use a dedicated function, 'gate_setup_timer()', to ensure that the timer is cancelled and re-initialized on action overwrite, and also ensure we initialize the timer in the error path of tcf_gate_init() v3: improve comment in the error path of tcf_gate_init() (thanks to Vladimir Oltean) v2: avoid 'goto' in gate_setup_timer (thanks to Cong Wang) CC: Ivan Vecera <[email protected]> Fixes: a01c245 ("net/sched: fix a couple of splats in the error path of tfc_gate_init()") Fixes: a51c328 ("net: qos: introduce a gate control flow action") Signed-off-by: Davide Caratti <[email protected]> Acked-by: Vladimir Oltean <[email protected]> Tested-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7024339 commit c362a06

File tree

1 file changed

+55
-35
lines changed

1 file changed

+55
-35
lines changed

net/sched/act_gate.c

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,27 @@ static int parse_gate_list(struct nlattr *list_attr,
272272
return err;
273273
}
274274

275+
static void gate_setup_timer(struct tcf_gate *gact, u64 basetime,
276+
enum tk_offsets tko, s32 clockid,
277+
bool do_init)
278+
{
279+
if (!do_init) {
280+
if (basetime == gact->param.tcfg_basetime &&
281+
tko == gact->tk_offset &&
282+
clockid == gact->param.tcfg_clockid)
283+
return;
284+
285+
spin_unlock_bh(&gact->tcf_lock);
286+
hrtimer_cancel(&gact->hitimer);
287+
spin_lock_bh(&gact->tcf_lock);
288+
}
289+
gact->param.tcfg_basetime = basetime;
290+
gact->param.tcfg_clockid = clockid;
291+
gact->tk_offset = tko;
292+
hrtimer_init(&gact->hitimer, clockid, HRTIMER_MODE_ABS_SOFT);
293+
gact->hitimer.function = gate_timer_func;
294+
}
295+
275296
static int tcf_gate_init(struct net *net, struct nlattr *nla,
276297
struct nlattr *est, struct tc_action **a,
277298
int ovr, int bind, bool rtnl_held,
@@ -303,6 +324,27 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
303324
if (!tb[TCA_GATE_PARMS])
304325
return -EINVAL;
305326

327+
if (tb[TCA_GATE_CLOCKID]) {
328+
clockid = nla_get_s32(tb[TCA_GATE_CLOCKID]);
329+
switch (clockid) {
330+
case CLOCK_REALTIME:
331+
tk_offset = TK_OFFS_REAL;
332+
break;
333+
case CLOCK_MONOTONIC:
334+
tk_offset = TK_OFFS_MAX;
335+
break;
336+
case CLOCK_BOOTTIME:
337+
tk_offset = TK_OFFS_BOOT;
338+
break;
339+
case CLOCK_TAI:
340+
tk_offset = TK_OFFS_TAI;
341+
break;
342+
default:
343+
NL_SET_ERR_MSG(extack, "Invalid 'clockid'");
344+
return -EINVAL;
345+
}
346+
}
347+
306348
parm = nla_data(tb[TCA_GATE_PARMS]);
307349
index = parm->index;
308350

@@ -326,10 +368,6 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
326368
tcf_idr_release(*a, bind);
327369
return -EEXIST;
328370
}
329-
if (ret == ACT_P_CREATED) {
330-
to_gate(*a)->param.tcfg_clockid = -1;
331-
INIT_LIST_HEAD(&(to_gate(*a)->param.entries));
332-
}
333371

334372
if (tb[TCA_GATE_PRIORITY])
335373
prio = nla_get_s32(tb[TCA_GATE_PRIORITY]);
@@ -340,33 +378,14 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
340378
if (tb[TCA_GATE_FLAGS])
341379
gflags = nla_get_u32(tb[TCA_GATE_FLAGS]);
342380

343-
if (tb[TCA_GATE_CLOCKID]) {
344-
clockid = nla_get_s32(tb[TCA_GATE_CLOCKID]);
345-
switch (clockid) {
346-
case CLOCK_REALTIME:
347-
tk_offset = TK_OFFS_REAL;
348-
break;
349-
case CLOCK_MONOTONIC:
350-
tk_offset = TK_OFFS_MAX;
351-
break;
352-
case CLOCK_BOOTTIME:
353-
tk_offset = TK_OFFS_BOOT;
354-
break;
355-
case CLOCK_TAI:
356-
tk_offset = TK_OFFS_TAI;
357-
break;
358-
default:
359-
NL_SET_ERR_MSG(extack, "Invalid 'clockid'");
360-
goto release_idr;
361-
}
362-
}
381+
gact = to_gate(*a);
382+
if (ret == ACT_P_CREATED)
383+
INIT_LIST_HEAD(&gact->param.entries);
363384

364385
err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
365386
if (err < 0)
366387
goto release_idr;
367388

368-
gact = to_gate(*a);
369-
370389
spin_lock_bh(&gact->tcf_lock);
371390
p = &gact->param;
372391

@@ -397,14 +416,10 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
397416
p->tcfg_cycletime_ext =
398417
nla_get_u64(tb[TCA_GATE_CYCLE_TIME_EXT]);
399418

419+
gate_setup_timer(gact, basetime, tk_offset, clockid,
420+
ret == ACT_P_CREATED);
400421
p->tcfg_priority = prio;
401-
p->tcfg_basetime = basetime;
402-
p->tcfg_clockid = clockid;
403422
p->tcfg_flags = gflags;
404-
405-
gact->tk_offset = tk_offset;
406-
hrtimer_init(&gact->hitimer, clockid, HRTIMER_MODE_ABS_SOFT);
407-
gact->hitimer.function = gate_timer_func;
408423
gate_get_start_time(gact, &start);
409424

410425
gact->current_close_time = start;
@@ -433,6 +448,13 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
433448
if (goto_ch)
434449
tcf_chain_put_by_act(goto_ch);
435450
release_idr:
451+
/* action is not inserted in any list: it's safe to init hitimer
452+
* without taking tcf_lock.
453+
*/
454+
if (ret == ACT_P_CREATED)
455+
gate_setup_timer(gact, gact->param.tcfg_basetime,
456+
gact->tk_offset, gact->param.tcfg_clockid,
457+
true);
436458
tcf_idr_release(*a, bind);
437459
return err;
438460
}
@@ -443,9 +465,7 @@ static void tcf_gate_cleanup(struct tc_action *a)
443465
struct tcf_gate_params *p;
444466

445467
p = &gact->param;
446-
if (p->tcfg_clockid != -1)
447-
hrtimer_cancel(&gact->hitimer);
448-
468+
hrtimer_cancel(&gact->hitimer);
449469
release_entry_list(&p->entries);
450470
}
451471

0 commit comments

Comments
 (0)