+
+#if DEBUG
+ error =
+#endif /* DEBUG */
+ m_copyback0(&m0, off, len, cp,
+ M_COPYBACK0_COPYBACK | M_COPYBACK0_EXTEND, M_DONTWAIT);
+
+#if DEBUG
+ if (error != 0 || (m0 != NULL && origm != m0))
+ panic("m_copyback");
+#endif /* DEBUG */
+}
+
+struct mbuf *
+m_copyback_cow(struct mbuf *m0, int off, int len, const void *cp, int how)
+{
+ int error;
+
+ /* don't support chain expansion */
+ VERIFY(off + len <= m_length(m0));
+
+ error = m_copyback0(&m0, off, len, cp,
+ M_COPYBACK0_COPYBACK | M_COPYBACK0_COW, how);
+ if (error) {
+ /*
+ * no way to recover from partial success.
+ * just free the chain.
+ */
+ m_freem(m0);
+ return (NULL);
+ }
+ return (m0);
+}
+
+/*
+ * m_makewritable: ensure the specified range writable.
+ */
+int
+m_makewritable(struct mbuf **mp, int off, int len, int how)
+{
+ int error;
+#if DEBUG
+ struct mbuf *n;
+ int origlen, reslen;
+
+ origlen = m_length(*mp);
+#endif /* DEBUG */
+
+#if 0 /* M_COPYALL is large enough */
+ if (len == M_COPYALL)
+ len = m_length(*mp) - off; /* XXX */
+#endif
+
+ error = m_copyback0(mp, off, len, NULL,
+ M_COPYBACK0_PRESERVE | M_COPYBACK0_COW, how);
+
+#if DEBUG
+ reslen = 0;
+ for (n = *mp; n; n = n->m_next)
+ reslen += n->m_len;
+ if (origlen != reslen)
+ panic("m_makewritable: length changed");
+ if (((*mp)->m_flags & M_PKTHDR) && reslen != (*mp)->m_pkthdr.len)
+ panic("m_makewritable: inconsist");
+#endif /* DEBUG */
+
+ return (error);
+}
+
+static int
+m_copyback0(struct mbuf **mp0, int off, int len, const void *vp, int flags,
+ int how)
+{
+ int mlen;
+ struct mbuf *m, *n;
+ struct mbuf **mp;
+ int totlen = 0;
+ const char *cp = vp;
+
+ VERIFY(mp0 != NULL);
+ VERIFY(*mp0 != NULL);
+ VERIFY((flags & M_COPYBACK0_PRESERVE) == 0 || cp == NULL);
+ VERIFY((flags & M_COPYBACK0_COPYBACK) == 0 || cp != NULL);
+
+ /*
+ * we don't bother to update "totlen" in the case of M_COPYBACK0_COW,
+ * assuming that M_COPYBACK0_EXTEND and M_COPYBACK0_COW are exclusive.
+ */
+
+ VERIFY((~flags & (M_COPYBACK0_EXTEND|M_COPYBACK0_COW)) != 0);
+
+ mp = mp0;
+ m = *mp;