int udp_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
 {
-       int copied = 0;
-
-       while (1) {
-               struct sk_buff *skb;
-               int err, used;
-
-               skb = skb_recv_udp(sk, MSG_DONTWAIT, &err);
-               if (!skb)
-                       return err;
+       struct sk_buff *skb;
+       int err, copied;
 
-               if (udp_lib_checksum_complete(skb)) {
-                       __UDP_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS,
-                                       IS_UDPLITE(sk));
-                       __UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS,
-                                       IS_UDPLITE(sk));
-                       atomic_inc(&sk->sk_drops);
-                       kfree_skb(skb);
-                       continue;
-               }
+try_again:
+       skb = skb_recv_udp(sk, MSG_DONTWAIT, &err);
+       if (!skb)
+               return err;
 
-               WARN_ON_ONCE(!skb_set_owner_sk_safe(skb, sk));
-               used = recv_actor(sk, skb);
-               if (used <= 0) {
-                       if (!copied)
-                               copied = used;
-                       kfree_skb(skb);
-                       break;
-               } else if (used <= skb->len) {
-                       copied += used;
-               }
+       if (udp_lib_checksum_complete(skb)) {
+               int is_udplite = IS_UDPLITE(sk);
+               struct net *net = sock_net(sk);
 
+               __UDP_INC_STATS(net, UDP_MIB_CSUMERRORS, is_udplite);
+               __UDP_INC_STATS(net, UDP_MIB_INERRORS, is_udplite);
+               atomic_inc(&sk->sk_drops);
                kfree_skb(skb);
-               break;
+               goto try_again;
        }
 
+       WARN_ON_ONCE(!skb_set_owner_sk_safe(skb, sk));
+       copied = recv_actor(sk, skb);
+       kfree_skb(skb);
+
        return copied;
 }
 EXPORT_SYMBOL(udp_read_skb);