Page MenuHomeFreeBSD

D44150.diff
No OneTemporary

D44150.diff

diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -1938,65 +1938,103 @@
/*
* Copy the contents of uio into a properly sized mbuf chain.
+ * A compat KPI. Users are recommended to use direct calls to backing
+ * functions.
*/
struct mbuf *
-m_uiotombuf(struct uio *uio, int how, int len, int align, int flags)
+m_uiotombuf(struct uio *uio, int how, int len, int lspace, int flags)
{
- struct mbuf *m, *mb;
- int error, length;
- ssize_t total;
- int progress = 0;
- if (flags & M_EXTPG)
- return (m_uiotombuf_nomap(uio, how, len, align, flags));
+ if (flags & M_EXTPG) {
+ /* XXX: 'lspace' magically becomes maxseg! */
+ return (m_uiotombuf_nomap(uio, how, len, lspace, flags));
+ } else if (__predict_false(uio->uio_resid + len == 0)) {
+ struct mbuf *m;
- /*
- * len can be zero or an arbitrary large value bound by
- * the total data supplied by the uio.
- */
- if (len > 0)
- total = (uio->uio_resid < len) ? uio->uio_resid : len;
+ /*
+ * m_uiotombuf() is known to return zero length buffer, keep
+ * this compatibility. mc_uiotomc() won't do that.
+ */
+ if (flags & M_PKTHDR) {
+ m = m_gethdr(how, MT_DATA);
+ m->m_pkthdr.memlen = MSIZE;
+ } else
+ m = m_get(how, MT_DATA);
+ if (m != NULL)
+ m->m_data += lspace;
+ return (m);
+ } else {
+ struct mchain mc;
+ int error;
+
+ error = mc_uiotomc(&mc, uio, len, lspace, how, flags);
+ if (__predict_true(error == 0)) {
+ if (flags & M_PKTHDR) {
+ mc_first(&mc)->m_pkthdr.len = mc.mc_len;
+ mc_first(&mc)->m_pkthdr.memlen = mc.mc_mlen;
+ }
+ return (mc_first(&mc));
+ } else
+ return (NULL);
+ }
+}
+
+/*
+ * Copy the contents of uio into a properly sized mbuf chain.
+ * In case of failure state of mchain is inconsistent.
+ * @param length Limit copyout length. If 0 entire uio_resid is copied.
+ * @param lspace Provide leading space in the first mbuf in the chain.
+ */
+int
+mc_uiotomc(struct mchain *mc, struct uio *uio, u_int length, u_int lspace,
+ int how, int flags)
+{
+ struct mbuf *mb;
+ u_int total;
+ int error;
+
+ MPASS(lspace < MHLEN);
+ MPASS(UINT_MAX - lspace >= length);
+ MPASS(uio->uio_rw == UIO_WRITE);
+ MPASS(uio->uio_resid >= 0);
+
+ if (length > 0) {
+ if (uio->uio_resid > length) {
+ total = length;
+ flags &= ~M_EOR;
+ } else
+ total = uio->uio_resid;
+ } else if (__predict_false(uio->uio_resid + lspace > UINT_MAX))
+ return (EOVERFLOW);
else
total = uio->uio_resid;
- /*
- * The smallest unit returned by m_getm2() is a single mbuf
- * with pkthdr. We can't align past it.
- */
- if (align >= MHLEN)
- return (NULL);
+ if (__predict_false(total + lspace == 0)) {
+ *mc = MCHAIN_INITIALIZER(mc);
+ return (0);
+ }
- /*
- * Give us the full allocation or nothing.
- * If len is zero return the smallest empty mbuf.
- */
- m = m_getm2(NULL, max(total + align, 1), how, MT_DATA, flags);
- if (m == NULL)
- return (NULL);
- m->m_data += align;
+ error = mc_get(mc, total + lspace, how, MT_DATA, flags);
+ if (__predict_false(error))
+ return (error);
+ mc_first(mc)->m_data += lspace;
/* Fill all mbufs with uio data and update header information. */
- for (mb = m; mb != NULL; mb = mb->m_next) {
- length = min(M_TRAILINGSPACE(mb), total - progress);
-
- error = uiomove(mtod(mb, void *), length, uio);
- if (error) {
- m_freem(m);
- return (NULL);
- }
+ STAILQ_FOREACH(mb, &mc->mc_q, m_stailq) {
+ u_int mlen;
- mb->m_len = length;
- progress += length;
- if (flags & M_PKTHDR) {
- m->m_pkthdr.len += length;
- m->m_pkthdr.memlen += MSIZE;
- if (mb->m_flags & M_EXT)
- m->m_pkthdr.memlen += mb->m_ext.ext_size;
+ mlen = min(M_TRAILINGSPACE(mb), total - mc->mc_len);
+ error = uiomove(mtod(mb, void *), mlen, uio);
+ if (__predict_false(error)) {
+ mc_freem(mc);
+ return (error);
}
+ mb->m_len = mlen;
+ mc->mc_len += mlen;
}
- KASSERT(progress == total, ("%s: progress != total", __func__));
+ MPASS(mc->mc_len == total);
- return (m);
+ return (0);
}
/*
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -1797,6 +1797,7 @@
int mc_get(struct mchain *, u_int, int, short, int);
int mc_split(struct mchain *, struct mchain *, u_int, int);
+int mc_uiotomc(struct mchain *, struct uio *, u_int, u_int, int, int);
#ifdef _SYS_TIMESPEC_H_
static inline void

File Metadata

Mime Type
text/plain
Expires
Fri, Jan 10, 3:24 PM (15 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15743727
Default Alt Text
D44150.diff (4 KB)

Event Timeline