From owner-svn-src-stable@FreeBSD.ORG Mon Aug 31 19:07:20 2009 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id F36BD106566B; Mon, 31 Aug 2009 19:07:19 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id DF8718FC12; Mon, 31 Aug 2009 19:07:19 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n7VJ7JHo036302; Mon, 31 Aug 2009 19:07:19 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n7VJ7J9Z036296; Mon, 31 Aug 2009 19:07:19 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <200908311907.n7VJ7J9Z036296@svn.freebsd.org> From: John Baldwin Date: Mon, 31 Aug 2009 19:07:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r196708 - in stable/7: share/man/man9 sys sys/conf sys/contrib/pf sys/kern sys/sys X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 31 Aug 2009 19:07:20 -0000 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 + * + * 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 + +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__ */