diff options
author | Peter Waskiewicz <peter.p.waskiewicz.jr@intel.com> | 2010-02-12 13:48:05 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-15 21:49:47 -0800 |
commit | e858911804f5ecadb41afd61582a11f68d416328 (patch) | |
tree | 71bf7f7ad187b2b06fe4e5d3c0494fdfaf67705d /net/core | |
parent | 02b1bae5e1c0f810168037be0134685085e95e88 (diff) | |
download | linux-e858911804f5ecadb41afd61582a11f68d416328.tar.bz2 |
ethtool: Fix filter addition when caching n-tuple filters
We can allow a filter to be added successfully to the underlying
hardware, but still return an error if the cached list memory
allocation fails. This patch fixes that condition.
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/ethtool.c | 40 |
1 files changed, 24 insertions, 16 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index a1280f643bf4..fbbe4b49116b 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -283,18 +283,17 @@ err_out: return ret; } -static int __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, - struct ethtool_rx_ntuple_flow_spec *spec) +static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, + struct ethtool_rx_ntuple_flow_spec *spec, + struct ethtool_rx_ntuple_flow_spec_container *fsc) { - struct ethtool_rx_ntuple_flow_spec_container *fsc; /* don't add filters forever */ - if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) - return 0; - - fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC); - if (!fsc) - return -ENOMEM; + if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) { + /* free the container */ + kfree(fsc); + return; + } /* Copy the whole filter over */ fsc->fs.flow_type = spec->flow_type; @@ -310,14 +309,13 @@ static int __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, /* add to the list */ list_add_tail_rcu(&fsc->list, &list->list); list->count++; - - return 0; } static int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr) { struct ethtool_rx_ntuple cmd; const struct ethtool_ops *ops = dev->ethtool_ops; + struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL; int ret; if (!ops->set_rx_ntuple) @@ -329,16 +327,26 @@ static int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr) if (copy_from_user(&cmd, useraddr, sizeof(cmd))) return -EFAULT; - ret = ops->set_rx_ntuple(dev, &cmd); - /* * Cache filter in dev struct for GET operation only if * the underlying driver doesn't have its own GET operation, and - * only if the filter was added successfully. + * only if the filter was added successfully. First make sure we + * can allocate the filter, then continue if successful. */ - if (!ops->get_rx_ntuple && !ret) - if (__rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs)) + if (!ops->get_rx_ntuple) { + fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC); + if (!fsc) return -ENOMEM; + } + + ret = ops->set_rx_ntuple(dev, &cmd); + if (ret) { + kfree(fsc); + return ret; + } + + if (!ops->get_rx_ntuple) + __rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs, fsc); return ret; } |