Commit 822d54b9 authored by Alexander Duyck's avatar Alexander Duyck Committed by David S. Miller

netpoll: Drop budget parameter from NAPI polling call hierarchy

For some reason we were carrying the budget value around between the
various calls to napi->poll.  If for example one of the drivers called had
a bug in which it returned a non-zero value for work this could result in
the budget value becoming negative.

Rather than carry around a value of budget that is 0 or less we can instead
just loop through and pass 0 to each napi->poll call.  If any driver
returns a value for work done that is non-zero then we can report that
driver and continue rather than allowing a bad actor to make the budget
value negative and pass that negative value to napi->poll.

Note, the only actual change here is that instead of letting budget become
negative we are keeping it at 0 regardless of the value returned for work
since it should not be possible for the polling routine to do any actual
work with a budget of 0.  So if the polling routine returns a non-0 value
we are just reporting it and continuing with a budget of 0 rather than
letting that work value be subtracted from the budget of 0.
Signed-off-by: default avatarAlexander Duyck <aduyck@mirantis.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2594e906
...@@ -140,7 +140,7 @@ static void queue_process(struct work_struct *work) ...@@ -140,7 +140,7 @@ static void queue_process(struct work_struct *work)
* case. Further, we test the poll_owner to avoid recursion on UP * case. Further, we test the poll_owner to avoid recursion on UP
* systems where the lock doesn't exist. * systems where the lock doesn't exist.
*/ */
static int poll_one_napi(struct napi_struct *napi, int budget) static void poll_one_napi(struct napi_struct *napi)
{ {
int work = 0; int work = 0;
...@@ -149,33 +149,33 @@ static int poll_one_napi(struct napi_struct *napi, int budget) ...@@ -149,33 +149,33 @@ static int poll_one_napi(struct napi_struct *napi, int budget)
* holding the napi->poll_lock. * holding the napi->poll_lock.
*/ */
if (!test_bit(NAPI_STATE_SCHED, &napi->state)) if (!test_bit(NAPI_STATE_SCHED, &napi->state))
return budget; return;
/* If we set this bit but see that it has already been set, /* If we set this bit but see that it has already been set,
* that indicates that napi has been disabled and we need * that indicates that napi has been disabled and we need
* to abort this operation * to abort this operation
*/ */
if (test_and_set_bit(NAPI_STATE_NPSVC, &napi->state)) if (test_and_set_bit(NAPI_STATE_NPSVC, &napi->state))
goto out; return;
work = napi->poll(napi, budget); /* We explicilty pass the polling call a budget of 0 to
WARN_ONCE(work > budget, "%pF exceeded budget in poll\n", napi->poll); * indicate that we are clearing the Tx path only.
*/
work = napi->poll(napi, 0);
WARN_ONCE(work, "%pF exceeded budget in poll\n", napi->poll);
trace_napi_poll(napi); trace_napi_poll(napi);
clear_bit(NAPI_STATE_NPSVC, &napi->state); clear_bit(NAPI_STATE_NPSVC, &napi->state);
out:
return budget - work;
} }
static void poll_napi(struct net_device *dev, int budget) static void poll_napi(struct net_device *dev)
{ {
struct napi_struct *napi; struct napi_struct *napi;
list_for_each_entry(napi, &dev->napi_list, dev_list) { list_for_each_entry(napi, &dev->napi_list, dev_list) {
if (napi->poll_owner != smp_processor_id() && if (napi->poll_owner != smp_processor_id() &&
spin_trylock(&napi->poll_lock)) { spin_trylock(&napi->poll_lock)) {
budget = poll_one_napi(napi, budget); poll_one_napi(napi);
spin_unlock(&napi->poll_lock); spin_unlock(&napi->poll_lock);
} }
} }
...@@ -185,7 +185,6 @@ static void netpoll_poll_dev(struct net_device *dev) ...@@ -185,7 +185,6 @@ static void netpoll_poll_dev(struct net_device *dev)
{ {
const struct net_device_ops *ops; const struct net_device_ops *ops;
struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo); struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo);
int budget = 0;
/* Don't do any rx activity if the dev_lock mutex is held /* Don't do any rx activity if the dev_lock mutex is held
* the dev_open/close paths use this to block netpoll activity * the dev_open/close paths use this to block netpoll activity
...@@ -208,7 +207,7 @@ static void netpoll_poll_dev(struct net_device *dev) ...@@ -208,7 +207,7 @@ static void netpoll_poll_dev(struct net_device *dev)
/* Process pending work on NIC */ /* Process pending work on NIC */
ops->ndo_poll_controller(dev); ops->ndo_poll_controller(dev);
poll_napi(dev, budget); poll_napi(dev);
up(&ni->dev_lock); up(&ni->dev_lock);
......
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