Commit 76b39b94 authored by Victor Nogueira's avatar Victor Nogueira Committed by Jakub Kicinski

net/sched: act_api: Notify user space if any actions were flushed before error

If during an action flush operation one of the actions is still being
referenced, the flush operation is aborted and the kernel returns to
user space with an error. However, if the kernel was able to flush, for
example, 3 actions and failed on the fourth, the kernel will not notify
user space that it deleted 3 actions before failing.

This patch fixes that behaviour by notifying user space of how many
actions were deleted before flush failed and by setting extack with a
message describing what happened.

Fixes: 55334a5d ("net_sched: act: refuse to remove bound action outside")
Signed-off-by: default avatarVictor Nogueira <victor@mojatatu.com>
Acked-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 8ee9d82c
...@@ -588,7 +588,8 @@ static int tcf_idr_release_unsafe(struct tc_action *p) ...@@ -588,7 +588,8 @@ static int tcf_idr_release_unsafe(struct tc_action *p)
} }
static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
const struct tc_action_ops *ops) const struct tc_action_ops *ops,
struct netlink_ext_ack *extack)
{ {
struct nlattr *nest; struct nlattr *nest;
int n_i = 0; int n_i = 0;
...@@ -604,20 +605,25 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, ...@@ -604,20 +605,25 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
if (nla_put_string(skb, TCA_KIND, ops->kind)) if (nla_put_string(skb, TCA_KIND, ops->kind))
goto nla_put_failure; goto nla_put_failure;
ret = 0;
mutex_lock(&idrinfo->lock); mutex_lock(&idrinfo->lock);
idr_for_each_entry_ul(idr, p, tmp, id) { idr_for_each_entry_ul(idr, p, tmp, id) {
if (IS_ERR(p)) if (IS_ERR(p))
continue; continue;
ret = tcf_idr_release_unsafe(p); ret = tcf_idr_release_unsafe(p);
if (ret == ACT_P_DELETED) { if (ret == ACT_P_DELETED)
module_put(ops->owner); module_put(ops->owner);
else if (ret < 0)
break;
n_i++; n_i++;
} else if (ret < 0) { }
mutex_unlock(&idrinfo->lock); mutex_unlock(&idrinfo->lock);
if (ret < 0) {
if (n_i)
NL_SET_ERR_MSG(extack, "Unable to flush all TC actions");
else
goto nla_put_failure; goto nla_put_failure;
} }
}
mutex_unlock(&idrinfo->lock);
ret = nla_put_u32(skb, TCA_FCNT, n_i); ret = nla_put_u32(skb, TCA_FCNT, n_i);
if (ret) if (ret)
...@@ -638,7 +644,7 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb, ...@@ -638,7 +644,7 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
struct tcf_idrinfo *idrinfo = tn->idrinfo; struct tcf_idrinfo *idrinfo = tn->idrinfo;
if (type == RTM_DELACTION) { if (type == RTM_DELACTION) {
return tcf_del_walker(idrinfo, skb, ops); return tcf_del_walker(idrinfo, skb, ops, extack);
} else if (type == RTM_GETACTION) { } else if (type == RTM_GETACTION) {
return tcf_dump_walker(idrinfo, skb, cb); return tcf_dump_walker(idrinfo, skb, cb);
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment