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 <[email protected]>
+ *
+ * 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__ */
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to