bnx2fc: do not add shared skbs to the fcoe_rx_list
[firefly-linux-kernel-4.4.55.git] / drivers / vhost / net.c
index f80d3dd41d8c6d420c8fb2d640a81739f2049674..c7fdabd0e5d312e2c85e5f2984be68fd504d8da3 100644 (file)
@@ -150,6 +150,11 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs)
 {
        kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal);
        wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount));
+}
+
+static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs)
+{
+       vhost_net_ubuf_put_and_wait(ubufs);
        kfree(ubufs);
 }
 
@@ -302,6 +307,11 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success)
        struct vhost_virtqueue *vq = ubufs->vq;
        int cnt = atomic_read(&ubufs->kref.refcount);
 
+       /* set len to mark this desc buffers done DMA */
+       vq->heads[ubuf->desc].len = success ?
+               VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN;
+       vhost_net_ubuf_put(ubufs);
+
        /*
         * Trigger polling thread if guest stopped submitting new buffers:
         * in this case, the refcount after decrement will eventually reach 1
@@ -312,10 +322,6 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success)
         */
        if (cnt <= 2 || !(cnt % 16))
                vhost_poll_queue(&vq->poll);
-       /* set len to mark this desc buffers done DMA */
-       vq->heads[ubuf->desc].len = success ?
-               VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN;
-       vhost_net_ubuf_put(ubufs);
 }
 
 /* Expects to be always run from workqueue - which acts as
@@ -507,9 +513,13 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
                        r = -ENOBUFS;
                        goto err;
                }
-               d = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
+               r = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
                                      ARRAY_SIZE(vq->iov) - seg, &out,
                                      &in, log, log_num);
+               if (unlikely(r < 0))
+                       goto err;
+
+               d = r;
                if (d == vq->num) {
                        r = 0;
                        goto err;
@@ -534,6 +544,12 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
        *iovcount = seg;
        if (unlikely(log))
                *log_num = nlogs;
+
+       /* Detect overrun */
+       if (unlikely(datalen > 0)) {
+               r = UIO_MAXIOV + 1;
+               goto err;
+       }
        return headcount;
 err:
        vhost_discard_vq_desc(vq, headcount);
@@ -589,6 +605,14 @@ static void handle_rx(struct vhost_net *net)
                /* On error, stop handling until the next kick. */
                if (unlikely(headcount < 0))
                        break;
+               /* On overrun, truncate and discard */
+               if (unlikely(headcount > UIO_MAXIOV)) {
+                       msg.msg_iovlen = 1;
+                       err = sock->ops->recvmsg(NULL, sock, &msg,
+                                                1, MSG_DONTWAIT | MSG_TRUNC);
+                       pr_debug("Discarded rx packet: len %zd\n", sock_len);
+                       continue;
+               }
                /* OK, now we need to know about added descriptors. */
                if (!headcount) {
                        if (unlikely(vhost_enable_notify(&net->dev, vq))) {
@@ -948,7 +972,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
        mutex_unlock(&vq->mutex);
 
        if (oldubufs) {
-               vhost_net_ubuf_put_and_wait(oldubufs);
+               vhost_net_ubuf_put_wait_and_free(oldubufs);
                mutex_lock(&vq->mutex);
                vhost_zerocopy_signal_used(n, vq);
                mutex_unlock(&vq->mutex);
@@ -966,7 +990,7 @@ err_used:
        rcu_assign_pointer(vq->private_data, oldsock);
        vhost_net_enable_vq(n, vq);
        if (ubufs)
-               vhost_net_ubuf_put_and_wait(ubufs);
+               vhost_net_ubuf_put_wait_and_free(ubufs);
 err_ubufs:
        fput(sock->file);
 err_vq: