Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107069439
D44150.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D44150.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D44150: mbuf: provide mc_uiotomc() a function to copy from uio(9) to mchain
Attached
Detach File
Event Timeline
Log In to Comment