diff options
author | David Vrabel <david.vrabel@citrix.com> | 2013-02-13 22:18:57 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-14 13:16:49 -0500 |
commit | 35876b5ffc154c357476b2c3bdab10feaf4bd8f0 (patch) | |
tree | 212f9ce2fa64a9dc2e25bdf29806dfc39e357cc9 /drivers/net/xen-netback/netback.c | |
parent | 306dbf9e5509da5aa8a787f13231442bc3ba697a (diff) |
xen-netback: correctly return errors from netbk_count_requests()
netbk_count_requests() could detect an error, call
netbk_fatal_tx_error() but return 0. The vif may then be used
afterwards (e.g., in a call to netbk_tx_error().
Since netbk_fatal_tx_error() could set vif->refcnt to 1, the vif may
be freed immediately after the call to netbk_fatal_tx_error() (e.g.,
if the vif is also removed).
Netback thread Xenwatch thread
-------------------------------------------
netbk_fatal_tx_err() netback_remove()
xenvif_disconnect()
...
free_netdev()
netbk_tx_err() Oops!
Signed-off-by: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Jan Beulich <JBeulich@suse.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Reported-by: Christopher S. Aker <caker@theshore.net>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/xen-netback/netback.c')
-rw-r--r-- | drivers/net/xen-netback/netback.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 2b9520c46e97..cd49ba949636 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
@@ -911,13 +911,13 @@ static int netbk_count_requests(struct xenvif *vif, | |||
911 | if (frags >= work_to_do) { | 911 | if (frags >= work_to_do) { |
912 | netdev_err(vif->dev, "Need more frags\n"); | 912 | netdev_err(vif->dev, "Need more frags\n"); |
913 | netbk_fatal_tx_err(vif); | 913 | netbk_fatal_tx_err(vif); |
914 | return -frags; | 914 | return -ENODATA; |
915 | } | 915 | } |
916 | 916 | ||
917 | if (unlikely(frags >= MAX_SKB_FRAGS)) { | 917 | if (unlikely(frags >= MAX_SKB_FRAGS)) { |
918 | netdev_err(vif->dev, "Too many frags\n"); | 918 | netdev_err(vif->dev, "Too many frags\n"); |
919 | netbk_fatal_tx_err(vif); | 919 | netbk_fatal_tx_err(vif); |
920 | return -frags; | 920 | return -E2BIG; |
921 | } | 921 | } |
922 | 922 | ||
923 | memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags), | 923 | memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags), |
@@ -925,7 +925,7 @@ static int netbk_count_requests(struct xenvif *vif, | |||
925 | if (txp->size > first->size) { | 925 | if (txp->size > first->size) { |
926 | netdev_err(vif->dev, "Frag is bigger than frame.\n"); | 926 | netdev_err(vif->dev, "Frag is bigger than frame.\n"); |
927 | netbk_fatal_tx_err(vif); | 927 | netbk_fatal_tx_err(vif); |
928 | return -frags; | 928 | return -EIO; |
929 | } | 929 | } |
930 | 930 | ||
931 | first->size -= txp->size; | 931 | first->size -= txp->size; |
@@ -935,7 +935,7 @@ static int netbk_count_requests(struct xenvif *vif, | |||
935 | netdev_err(vif->dev, "txp->offset: %x, size: %u\n", | 935 | netdev_err(vif->dev, "txp->offset: %x, size: %u\n", |
936 | txp->offset, txp->size); | 936 | txp->offset, txp->size); |
937 | netbk_fatal_tx_err(vif); | 937 | netbk_fatal_tx_err(vif); |
938 | return -frags; | 938 | return -EINVAL; |
939 | } | 939 | } |
940 | } while ((txp++)->flags & XEN_NETTXF_more_data); | 940 | } while ((txp++)->flags & XEN_NETTXF_more_data); |
941 | return frags; | 941 | return frags; |