]> Git Repo - linux.git/blobdiff - drivers/net/xen-netback/netback.c
selinux: Remove security_ops extern
[linux.git] / drivers / net / xen-netback / netback.c
index 49efff9b99f49f6d34bbe72b0414b0d8ddec849f..c65b636bcab9dfb3bdf3528bd3d0fcd30f7a5812 100644 (file)
@@ -168,7 +168,8 @@ bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue, int needed)
  * adding 'size' bytes to a buffer which currently contains 'offset'
  * bytes.
  */
-static bool start_new_rx_buffer(int offset, unsigned long size, int head)
+static bool start_new_rx_buffer(int offset, unsigned long size, int head,
+                               bool full_coalesce)
 {
        /* simple case: we have completely filled the current buffer. */
        if (offset == MAX_BUFFER_OFFSET)
@@ -180,6 +181,7 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head)
         *     (i)   this frag would fit completely in the next buffer
         * and (ii)  there is already some data in the current buffer
         * and (iii) this is not the head buffer.
+        * and (iv)  there is no need to fully utilize the buffers
         *
         * Where:
         * - (i) stops us splitting a frag into two copies
@@ -190,6 +192,8 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head)
         *   by (ii) but is explicitly checked because
         *   netfront relies on the first buffer being
         *   non-empty and can crash otherwise.
+        * - (iv) is needed for skbs which can use up more than MAX_SKB_FRAGS
+        *   slot
         *
         * This means we will effectively linearise small
         * frags but do not needlessly split large buffers
@@ -197,7 +201,8 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head)
         * own buffers as before.
         */
        BUG_ON(size > MAX_BUFFER_OFFSET);
-       if ((offset + size > MAX_BUFFER_OFFSET) && offset && !head)
+       if ((offset + size > MAX_BUFFER_OFFSET) && offset && !head &&
+           !full_coalesce)
                return true;
 
        return false;
@@ -232,6 +237,13 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue,
        return meta;
 }
 
+struct xenvif_rx_cb {
+       int meta_slots_used;
+       bool full_coalesce;
+};
+
+#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb)
+
 /*
  * Set up the grant operations for this fragment. If it's a flipping
  * interface, we also set up the unmap request from here.
@@ -266,7 +278,10 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb
                if (bytes > size)
                        bytes = size;
 
-               if (start_new_rx_buffer(npo->copy_off, bytes, *head)) {
+               if (start_new_rx_buffer(npo->copy_off,
+                                       bytes,
+                                       *head,
+                                       XENVIF_RX_CB(skb)->full_coalesce)) {
                        /*
                         * Netfront requires there to be some data in the head
                         * buffer.
@@ -548,12 +563,6 @@ static void xenvif_add_frag_responses(struct xenvif_queue *queue, int status,
        }
 }
 
-struct xenvif_rx_cb {
-       int meta_slots_used;
-};
-
-#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb)
-
 void xenvif_kick_thread(struct xenvif_queue *queue)
 {
        wake_up(&queue->wq);
@@ -609,10 +618,15 @@ static void xenvif_rx_action(struct xenvif_queue *queue)
 
                /* To avoid the estimate becoming too pessimal for some
                 * frontends that limit posted rx requests, cap the estimate
-                * at MAX_SKB_FRAGS.
+                * at MAX_SKB_FRAGS. In this case netback will fully coalesce
+                * the skb into the provided slots.
                 */
-               if (max_slots_needed > MAX_SKB_FRAGS)
+               if (max_slots_needed > MAX_SKB_FRAGS) {
                        max_slots_needed = MAX_SKB_FRAGS;
+                       XENVIF_RX_CB(skb)->full_coalesce = true;
+               } else {
+                       XENVIF_RX_CB(skb)->full_coalesce = false;
+               }
 
                /* We may need one more slot for GSO metadata */
                if (skb_is_gso(skb) &&
@@ -1016,14 +1030,21 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
 {
        struct gnttab_map_grant_ref *gop_map = *gopp_map;
        u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+       /* This always points to the shinfo of the skb being checked, which
+        * could be either the first or the one on the frag_list
+        */
        struct skb_shared_info *shinfo = skb_shinfo(skb);
+       /* If this is non-NULL, we are currently checking the frag_list skb, and
+        * this points to the shinfo of the first one
+        */
+       struct skb_shared_info *first_shinfo = NULL;
        int nr_frags = shinfo->nr_frags;
+       const bool sharedslot = nr_frags &&
+                               frag_get_pending_idx(&shinfo->frags[0]) == pending_idx;
        int i, err;
-       struct sk_buff *first_skb = NULL;
 
        /* Check status of header. */
        err = (*gopp_copy)->status;
-       (*gopp_copy)++;
        if (unlikely(err)) {
                if (net_ratelimit())
                        netdev_dbg(queue->vif->dev,
@@ -1031,8 +1052,12 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
                                   (*gopp_copy)->status,
                                   pending_idx,
                                   (*gopp_copy)->source.u.ref);
-               xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_ERROR);
+               /* The first frag might still have this slot mapped */
+               if (!sharedslot)
+                       xenvif_idx_release(queue, pending_idx,
+                                          XEN_NETIF_RSP_ERROR);
        }
+       (*gopp_copy)++;
 
 check_frags:
        for (i = 0; i < nr_frags; i++, gop_map++) {
@@ -1048,8 +1073,19 @@ check_frags:
                                                pending_idx,
                                                gop_map->handle);
                        /* Had a previous error? Invalidate this fragment. */
-                       if (unlikely(err))
+                       if (unlikely(err)) {
                                xenvif_idx_unmap(queue, pending_idx);
+                               /* If the mapping of the first frag was OK, but
+                                * the header's copy failed, and they are
+                                * sharing a slot, send an error
+                                */
+                               if (i == 0 && sharedslot)
+                                       xenvif_idx_release(queue, pending_idx,
+                                                          XEN_NETIF_RSP_ERROR);
+                               else
+                                       xenvif_idx_release(queue, pending_idx,
+                                                          XEN_NETIF_RSP_OKAY);
+                       }
                        continue;
                }
 
@@ -1061,42 +1097,53 @@ check_frags:
                                   gop_map->status,
                                   pending_idx,
                                   gop_map->ref);
+
                xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_ERROR);
 
                /* Not the first error? Preceding frags already invalidated. */
                if (err)
                        continue;
-               /* First error: invalidate preceding fragments. */
+
+               /* First error: if the header haven't shared a slot with the
+                * first frag, release it as well.
+                */
+               if (!sharedslot)
+                       xenvif_idx_release(queue,
+                                          XENVIF_TX_CB(skb)->pending_idx,
+                                          XEN_NETIF_RSP_OKAY);
+
+               /* Invalidate preceding fragments of this skb. */
                for (j = 0; j < i; j++) {
                        pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
                        xenvif_idx_unmap(queue, pending_idx);
+                       xenvif_idx_release(queue, pending_idx,
+                                          XEN_NETIF_RSP_OKAY);
+               }
+
+               /* And if we found the error while checking the frag_list, unmap
+                * the first skb's frags
+                */
+               if (first_shinfo) {
+                       for (j = 0; j < first_shinfo->nr_frags; j++) {
+                               pending_idx = frag_get_pending_idx(&first_shinfo->frags[j]);
+                               xenvif_idx_unmap(queue, pending_idx);
+                               xenvif_idx_release(queue, pending_idx,
+                                                  XEN_NETIF_RSP_OKAY);
+                       }
                }
 
                /* Remember the error: invalidate all subsequent fragments. */
                err = newerr;
        }
 
-       if (skb_has_frag_list(skb)) {
-               first_skb = skb;
-               skb = shinfo->frag_list;
-               shinfo = skb_shinfo(skb);
+       if (skb_has_frag_list(skb) && !first_shinfo) {
+               first_shinfo = skb_shinfo(skb);
+               shinfo = skb_shinfo(skb_shinfo(skb)->frag_list);
                nr_frags = shinfo->nr_frags;
 
                goto check_frags;
        }
 
-       /* There was a mapping error in the frag_list skb. We have to unmap
-        * the first skb's frags
-        */
-       if (first_skb && err) {
-               int j;
-               shinfo = skb_shinfo(first_skb);
-               for (j = 0; j < shinfo->nr_frags; j++) {
-                       pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
-                       xenvif_idx_unmap(queue, pending_idx);
-               }
-       }
-
        *gopp_map = gop_map;
        return err;
 }
@@ -1504,7 +1551,16 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
 
                /* Check the remap error code. */
                if (unlikely(xenvif_tx_check_gop(queue, skb, &gop_map, &gop_copy))) {
+                       /* If there was an error, xenvif_tx_check_gop is
+                        * expected to release all the frags which were mapped,
+                        * so kfree_skb shouldn't do it again
+                        */
                        skb_shinfo(skb)->nr_frags = 0;
+                       if (skb_has_frag_list(skb)) {
+                               struct sk_buff *nskb =
+                                               skb_shinfo(skb)->frag_list;
+                               skb_shinfo(nskb)->nr_frags = 0;
+                       }
                        kfree_skb(skb);
                        continue;
                }
@@ -1808,8 +1864,6 @@ void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx)
                           tx_unmap_op.status);
                BUG();
        }
-
-       xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_OKAY);
 }
 
 static inline int rx_work_todo(struct xenvif_queue *queue)
This page took 0.034955 seconds and 4 git commands to generate.