}
 }
 
+static inline u32 sk_msg_iter_dist(u32 start, u32 end)
+{
+       return end >= start ? end - start : end + (MAX_MSG_FRAGS - start);
+}
+
 #define sk_msg_iter_var_prev(var)                      \
        do {                                            \
                if (var == 0)                           \
        if (sk_msg_full(msg))
                return MAX_MSG_FRAGS;
 
-       return msg->sg.end >= msg->sg.start ?
-               msg->sg.end - msg->sg.start :
-               msg->sg.end + (MAX_MSG_FRAGS - msg->sg.start);
+       return sk_msg_iter_dist(msg->sg.start, msg->sg.end);
 }
 
 static inline struct scatterlist *sk_msg_elem(struct sk_msg *msg, int which)
 
 
        msg->sg.data[i].length -= trim;
        sk_mem_uncharge(sk, trim);
+       /* Adjust copybreak if it falls into the trimmed part of last buf */
+       if (msg->sg.curr == i && msg->sg.copybreak > msg->sg.data[i].length)
+               msg->sg.copybreak = msg->sg.data[i].length;
 out:
-       /* If we trim data before curr pointer update copybreak and current
-        * so that any future copy operations start at new copy location.
+       sk_msg_iter_var_next(i);
+       msg->sg.end = i;
+
+       /* If we trim data a full sg elem before curr pointer update
+        * copybreak and current so that any future copy operations
+        * start at new copy location.
         * However trimed data that has not yet been used in a copy op
         * does not require an update.
         */
-       if (msg->sg.curr >= i) {
+       if (!msg->sg.size) {
+               msg->sg.curr = msg->sg.start;
+               msg->sg.copybreak = 0;
+       } else if (sk_msg_iter_dist(msg->sg.start, msg->sg.curr) >=
+                  sk_msg_iter_dist(msg->sg.start, msg->sg.end)) {
+               sk_msg_iter_var_prev(i);
                msg->sg.curr = i;
                msg->sg.copybreak = msg->sg.data[i].length;
        }
-       sk_msg_iter_var_next(i);
-       msg->sg.end = i;
 }
 EXPORT_SYMBOL_GPL(sk_msg_trim);