svn commit: r196708 - in stable/7: share/man/man9 sys sys/conf
sys/contrib/pf sys/kern sys/sys
John Baldwin
jhb at FreeBSD.org
Mon Aug 31 19:07:20 UTC 2009
Author: jhb
Date: Mon Aug 31 19:07:19 2009
New Revision: 196708
URL: http://svn.freebsd.org/changeset/base/196708
Log:
MFC 193260 and 196417:
Add a simple API to manage scatter/gather lists of phyiscal addresses.
Each list describes a logical memory object that is backed by one or more
physical address ranges. To minimize locking, the sglist objects
themselves are immutable once they are shared.
Added:
stable/7/share/man/man9/sglist.9
- copied, changed from r193260, head/share/man/man9/sglist.9
stable/7/sys/kern/subr_sglist.c
- copied, changed from r193260, head/sys/kern/subr_sglist.c
stable/7/sys/sys/sglist.h
- copied unchanged from r193260, head/sys/sys/sglist.h
Modified:
stable/7/share/man/man9/ (props changed)
stable/7/share/man/man9/Makefile
stable/7/sys/ (props changed)
stable/7/sys/conf/files
stable/7/sys/contrib/pf/ (props changed)
Modified: stable/7/share/man/man9/Makefile
==============================================================================
--- stable/7/share/man/man9/Makefile Mon Aug 31 18:41:13 2009 (r196707)
+++ stable/7/share/man/man9/Makefile Mon Aug 31 19:07:19 2009 (r196708)
@@ -210,6 +210,7 @@ MAN= accept_filter.9 \
selrecord.9 \
sema.9 \
sf_buf.9 \
+ sglist.9 \
signal.9 \
sleep.9 \
sleepqueue.9 \
@@ -983,6 +984,24 @@ MLINKS+=sf_buf.9 sf_buf_alloc.9 \
sf_buf.9 sf_buf_free.9 \
sf_buf.9 sf_buf_kva.9 \
sf_buf.9 sf_buf_page.9
+MLINKS+=sglist.9 sglist_alloc.9 \
+ sglist.9 sglist_append.9 \
+ sglist.9 sglist_append_mbuf.9 \
+ sglist.9 sglist_append_phys.9 \
+ sglist.9 sglist_append_uio.9 \
+ sglist.9 sglist_append_user.9 \
+ sglist.9 sglist_build.9 \
+ sglist.9 sglist_clone.9 \
+ sglist.9 sglist_consume_uio.9 \
+ sglist.9 sglist_count.9 \
+ sglist.9 sglist_free.9 \
+ sglist.9 sglist_hold.9 \
+ sglist.9 sglist_init.9 \
+ sglist.9 sglist_join.9 \
+ sglist.9 sglist_length.9 \
+ sglist.9 sglist_reset.9 \
+ sglist.9 sglist_slice.9 \
+ sglist.9 sglist_split.9
MLINKS+=signal.9 cursig.9 \
signal.9 execsigs.9 \
signal.9 issignal.9 \
Copied and modified: stable/7/share/man/man9/sglist.9 (from r193260, head/share/man/man9/sglist.9)
==============================================================================
--- head/share/man/man9/sglist.9 Mon Jun 1 20:35:39 2009 (r193260, copy source)
+++ stable/7/share/man/man9/sglist.9 Mon Aug 31 19:07:19 2009 (r196708)
@@ -191,6 +191,8 @@ Specifically, the
family of routines can be used to append the physical address ranges described
by an object to the end of a scatter/gather list.
All of these routines return 0 on success or an error on failure.
+If a request to append an address range to a scatter/gather list fails,
+the scatter/gather list will remain unchanged.
.Pp
The
.Nm sglist_append
@@ -445,6 +447,7 @@ There are not enough available segments
to append the physical address ranges from
.Fa second .
.El
+.Pp
The
.Nm sglist_slice
function returns the following errors on failure:
@@ -470,6 +473,7 @@ list in
.Fa *slice
to describe the requested physical address ranges.
.El
+.Pp
The
.Nm sglist_split
function returns the following errors on failure:
Modified: stable/7/sys/conf/files
==============================================================================
--- stable/7/sys/conf/files Mon Aug 31 18:41:13 2009 (r196707)
+++ stable/7/sys/conf/files Mon Aug 31 19:07:19 2009 (r196708)
@@ -1630,6 +1630,7 @@ kern/kern_proc.c standard
kern/kern_prot.c standard
kern/kern_resource.c standard
kern/kern_rwlock.c standard
+kern/kern_sdt.c optional kdtrace_hooks
kern/kern_sema.c standard
kern/kern_shutdown.c standard
kern/kern_sig.c standard
@@ -1683,7 +1684,7 @@ kern/subr_rman.c standard
kern/subr_rtc.c optional genclock
kern/subr_sbuf.c standard
kern/subr_scanf.c standard
-kern/kern_sdt.c optional kdtrace_hooks
+kern/subr_sglist.c standard
kern/subr_sleepqueue.c standard
kern/subr_smp.c standard
kern/subr_stack.c optional ddb | stack
Copied and modified: stable/7/sys/kern/subr_sglist.c (from r193260, head/sys/kern/subr_sglist.c)
==============================================================================
--- head/sys/kern/subr_sglist.c Mon Jun 1 20:35:39 2009 (r193260, copy source)
+++ stable/7/sys/kern/subr_sglist.c Mon Aug 31 19:07:19 2009 (r196708)
@@ -48,6 +48,32 @@ __FBSDID("$FreeBSD$");
static MALLOC_DEFINE(M_SGLIST, "sglist", "scatter/gather lists");
/*
+ * Convenience macros to save the state of an sglist so it can be restored
+ * if an append attempt fails. Since sglist's only grow we only need to
+ * save the current count of segments and the length of the ending segment.
+ * Earlier segments will not be changed by an append, and the only change
+ * that can occur to the ending segment is that it can be extended.
+ */
+struct sgsave {
+ u_short sg_nseg;
+ size_t ss_len;
+};
+
+#define SGLIST_SAVE(sg, sgsave) do { \
+ (sgsave).sg_nseg = (sg)->sg_nseg; \
+ if ((sgsave).sg_nseg > 0) \
+ (sgsave).ss_len = (sg)->sg_segs[(sgsave).sg_nseg - 1].ss_len; \
+ else \
+ (sgsave).ss_len = 0; \
+} while (0)
+
+#define SGLIST_RESTORE(sg, sgsave) do { \
+ (sg)->sg_nseg = (sgsave).sg_nseg; \
+ if ((sgsave).sg_nseg > 0) \
+ (sg)->sg_segs[(sgsave).sg_nseg - 1].ss_len = (sgsave).ss_len; \
+} while (0)
+
+/*
* Append a single (paddr, len) to a sglist. sg is the list and ss is
* the current segment in the list. If we run out of segments then
* EFBIG will be returned.
@@ -62,10 +88,8 @@ _sglist_append_range(struct sglist *sg,
if (ss->ss_paddr + ss->ss_len == paddr)
ss->ss_len += len;
else {
- if (sg->sg_nseg == sg->sg_maxseg) {
- sg->sg_nseg = 0;
+ if (sg->sg_nseg == sg->sg_maxseg)
return (EFBIG);
- }
ss++;
ss->ss_paddr = paddr;
ss->ss_len = len;
@@ -107,26 +131,33 @@ _sglist_append_buf(struct sglist *sg, vo
ss->ss_paddr = paddr;
ss->ss_len = seglen;
sg->sg_nseg = 1;
- error = 0;
} else {
ss = &sg->sg_segs[sg->sg_nseg - 1];
error = _sglist_append_range(sg, &ss, paddr, seglen);
+ if (error)
+ return (error);
}
+ vaddr += seglen;
+ len -= seglen;
+ if (donep)
+ *donep += seglen;
- while (error == 0 && len > seglen) {
- vaddr += seglen;
- len -= seglen;
- if (donep)
- *donep += seglen;
+ while (len > 0) {
seglen = MIN(len, PAGE_SIZE);
if (pmap != NULL)
paddr = pmap_extract(pmap, vaddr);
else
paddr = pmap_kextract(vaddr);
error = _sglist_append_range(sg, &ss, paddr, seglen);
+ if (error)
+ return (error);
+ vaddr += seglen;
+ len -= seglen;
+ if (donep)
+ *donep += seglen;
}
- return (error);
+ return (0);
}
/*
@@ -195,10 +226,16 @@ sglist_free(struct sglist *sg)
int
sglist_append(struct sglist *sg, void *buf, size_t len)
{
+ struct sgsave save;
+ int error;
if (sg->sg_maxseg == 0)
return (EINVAL);
- return (_sglist_append_buf(sg, buf, len, NULL, NULL));
+ SGLIST_SAVE(sg, save);
+ error = _sglist_append_buf(sg, buf, len, NULL, NULL);
+ if (error)
+ SGLIST_RESTORE(sg, save);
+ return (error);
}
/*
@@ -209,6 +246,8 @@ int
sglist_append_phys(struct sglist *sg, vm_paddr_t paddr, size_t len)
{
struct sglist_seg *ss;
+ struct sgsave save;
+ int error;
if (sg->sg_maxseg == 0)
return (EINVAL);
@@ -222,7 +261,11 @@ sglist_append_phys(struct sglist *sg, vm
return (0);
}
ss = &sg->sg_segs[sg->sg_nseg - 1];
- return (_sglist_append_range(sg, &ss, paddr, len));
+ SGLIST_SAVE(sg, save);
+ error = _sglist_append_range(sg, &ss, paddr, len);
+ if (error)
+ SGLIST_RESTORE(sg, save);
+ return (error);
}
/*
@@ -233,6 +276,7 @@ sglist_append_phys(struct sglist *sg, vm
int
sglist_append_mbuf(struct sglist *sg, struct mbuf *m0)
{
+ struct sgsave save;
struct mbuf *m;
int error;
@@ -240,11 +284,14 @@ sglist_append_mbuf(struct sglist *sg, st
return (EINVAL);
error = 0;
+ SGLIST_SAVE(sg, save);
for (m = m0; m != NULL; m = m->m_next) {
if (m->m_len > 0) {
error = sglist_append(sg, m->m_data, m->m_len);
- if (error)
+ if (error) {
+ SGLIST_RESTORE(sg, save);
return (error);
+ }
}
}
return (0);
@@ -258,11 +305,17 @@ sglist_append_mbuf(struct sglist *sg, st
int
sglist_append_user(struct sglist *sg, void *buf, size_t len, struct thread *td)
{
+ struct sgsave save;
+ int error;
if (sg->sg_maxseg == 0)
return (EINVAL);
- return (_sglist_append_buf(sg, buf, len,
- vmspace_pmap(td->td_proc->p_vmspace), NULL));
+ SGLIST_SAVE(sg, save);
+ error = _sglist_append_buf(sg, buf, len,
+ vmspace_pmap(td->td_proc->p_vmspace), NULL);
+ if (error)
+ SGLIST_RESTORE(sg, save);
+ return (error);
}
/*
@@ -274,6 +327,7 @@ int
sglist_append_uio(struct sglist *sg, struct uio *uio)
{
struct iovec *iov;
+ struct sgsave save;
size_t resid, minlen;
pmap_t pmap;
int error, i;
@@ -292,6 +346,7 @@ sglist_append_uio(struct sglist *sg, str
pmap = NULL;
error = 0;
+ SGLIST_SAVE(sg, save);
for (i = 0; i < uio->uio_iovcnt && resid != 0; i++) {
/*
* Now at the first iovec to load. Load each iovec
@@ -301,8 +356,10 @@ sglist_append_uio(struct sglist *sg, str
if (minlen > 0) {
error = _sglist_append_buf(sg, iov[i].iov_base, minlen,
pmap, NULL);
- if (error)
+ if (error) {
+ SGLIST_RESTORE(sg, save);
return (error);
+ }
resid -= minlen;
}
}
@@ -397,6 +454,7 @@ sglist_clone(struct sglist *sg, int mfla
new = sglist_alloc(sg->sg_maxseg, mflags);
if (new == NULL)
return (NULL);
+ new->sg_nseg = sg->sg_nseg;
bcopy(sg->sg_segs, new->sg_segs, sizeof(struct sglist_seg) *
sg->sg_nseg);
return (new);
Copied: stable/7/sys/sys/sglist.h (from r193260, head/sys/sys/sglist.h)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/7/sys/sys/sglist.h Mon Aug 31 19:07:19 2009 (r196708, copy of r193260, head/sys/sys/sglist.h)
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb at FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * A scatter/gather list describes a group of physical address ranges.
+ * Each physical address range consists of a starting address and a
+ * length.
+ */
+
+#ifndef __SGLIST_H__
+#define __SGLIST_H__
+
+#include <sys/refcount.h>
+
+struct sglist_seg {
+ vm_paddr_t ss_paddr;
+ size_t ss_len;
+};
+
+struct sglist {
+ struct sglist_seg *sg_segs;
+ int sg_refs;
+ u_short sg_nseg;
+ u_short sg_maxseg;
+};
+
+struct mbuf;
+struct uio;
+
+static __inline void
+sglist_init(struct sglist *sg, u_short maxsegs, struct sglist_seg *segs)
+{
+
+ sg->sg_segs = segs;
+ sg->sg_nseg = 0;
+ sg->sg_maxseg = maxsegs;
+ refcount_init(&sg->sg_refs, 1);
+}
+
+static __inline void
+sglist_reset(struct sglist *sg)
+{
+
+ sg->sg_nseg = 0;
+}
+
+static __inline struct sglist *
+sglist_hold(struct sglist *sg)
+{
+
+ refcount_acquire(&sg->sg_refs);
+ return (sg);
+}
+
+struct sglist *sglist_alloc(int nsegs, int mflags);
+int sglist_append(struct sglist *sg, void *buf, size_t len);
+int sglist_append_mbuf(struct sglist *sg, struct mbuf *m0);
+int sglist_append_phys(struct sglist *sg, vm_paddr_t paddr,
+ size_t len);
+int sglist_append_uio(struct sglist *sg, struct uio *uio);
+int sglist_append_user(struct sglist *sg, void *buf, size_t len,
+ struct thread *td);
+struct sglist *sglist_build(void *buf, size_t len, int mflags);
+struct sglist *sglist_clone(struct sglist *sg, int mflags);
+int sglist_consume_uio(struct sglist *sg, struct uio *uio, int resid);
+int sglist_count(void *buf, size_t len);
+void sglist_free(struct sglist *sg);
+int sglist_join(struct sglist *first, struct sglist *second);
+size_t sglist_length(struct sglist *sg);
+int sglist_slice(struct sglist *original, struct sglist **slice,
+ size_t offset, size_t length, int mflags);
+int sglist_split(struct sglist *original, struct sglist **head,
+ size_t length, int mflags);
+
+#endif /* !__SGLIST_H__ */
More information about the svn-src-stable
mailing list