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-7 mailing list