From owner-svn-src-all@freebsd.org Fri May 20 23:28:44 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 90F58B43DD4; Fri, 20 May 2016 23:28:44 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 53942111A; Fri, 20 May 2016 23:28:44 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u4KNShQq094229; Fri, 20 May 2016 23:28:43 GMT (envelope-from jhb@FreeBSD.org) Received: (from jhb@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u4KNShU9094225; Fri, 20 May 2016 23:28:43 GMT (envelope-from jhb@FreeBSD.org) Message-Id: <201605202328.u4KNShU9094225@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: jhb set sender to jhb@FreeBSD.org using -f From: John Baldwin Date: Fri, 20 May 2016 23:28:43 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r300337 - in head: share/man/man9 sys/kern sys/sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 May 2016 23:28:44 -0000 Author: jhb Date: Fri May 20 23:28:43 2016 New Revision: 300337 URL: https://svnweb.freebsd.org/changeset/base/300337 Log: Add sglist functions for working with arrays of VM pages. sglist_count_vmpages() determines the number of segments required for a buffer described by an array of VM pages. sglist_append_vmpages() adds the segments described by such a buffer to an sglist. The latter function is largely pulled from sglist_append_bio(), and sglist_append_bio() now uses sglist_append_vmpages(). Reviewed by: kib Sponsored by: Chelsio Communications Modified: head/share/man/man9/Makefile head/share/man/man9/sglist.9 head/sys/kern/subr_sglist.c head/sys/sys/sglist.h Modified: head/share/man/man9/Makefile ============================================================================== --- head/share/man/man9/Makefile Fri May 20 23:08:22 2016 (r300336) +++ head/share/man/man9/Makefile Fri May 20 23:28:43 2016 (r300337) @@ -1510,10 +1510,12 @@ MLINKS+=sglist.9 sglist_alloc.9 \ sglist.9 sglist_append_phys.9 \ sglist.9 sglist_append_uio.9 \ sglist.9 sglist_append_user.9 \ + sglist.9 sglist_append_vmpages.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_count_vmpages.9 \ sglist.9 sglist_free.9 \ sglist.9 sglist_hold.9 \ sglist.9 sglist_init.9 \ Modified: head/share/man/man9/sglist.9 ============================================================================== --- head/share/man/man9/sglist.9 Fri May 20 23:08:22 2016 (r300336) +++ head/share/man/man9/sglist.9 Fri May 20 23:28:43 2016 (r300337) @@ -38,10 +38,12 @@ .Nm sglist_append_phys , .Nm sglist_append_uio , .Nm sglist_append_user , +.Nm sglist_append_vmpages , .Nm sglist_build , .Nm sglist_clone , .Nm sglist_consume_uio , .Nm sglist_count , +.Nm sglist_count_vmpages , .Nm sglist_free , .Nm sglist_hold , .Nm sglist_init , @@ -68,6 +70,8 @@ .Fn sglist_append_uio "struct sglist *sg" "struct uio *uio" .Ft int .Fn sglist_append_user "struct sglist *sg" "void *buf" "size_t len" "struct thread *td" +.Ft int +.Fn sglist_append_vmpages "struct sglist *sg" "vm_page_t *m" "size_t pgoff" "size_t len" .Ft struct sglist * .Fn sglist_build "void *buf" "size_t len" "int mflags" .Ft struct sglist * @@ -76,6 +80,8 @@ .Fn sglist_consume_uio "struct sglist *sg" "struct uio *uio" "size_t resid" .Ft int .Fn sglist_count "void *buf" "size_t len" +.Ft int +.Fn sglist_count_vmpages "vm_page_t *m" "size_t pgoff" "size_t len" .Ft void .Fn sglist_free "struct sglist *sg" .Ft struct sglist * @@ -137,6 +143,18 @@ and is bytes long. .Pp The +.Nm sglist_count_vmpages +function returns the number of scatter/gather list elements needed to describe +the physical address ranges of a buffer backed by an array of virtual memory +pages +.Fa m . +The buffer starts at an offset of +.Fa pgoff +bytes relative to the first page and is +.Fa len +bytes long. +.Pp +The .Nm sglist_build function allocates a new scatter/gather list object that describes the physical address ranges mapped by a single kernel virtual address range. @@ -262,6 +280,17 @@ the user buffer are wired for the lifeti .Fa sg . .Pp The +.Nm sglist_append_vmpages +function appends the physical address ranges of a buffer backed by an array +of virtual memory pages +.Fa m . +The buffer starts at an offset of +.Fa pgoff +bytes relative to the first page and is +.Fa len +bytes long. +.Pp +The .Nm sglist_consume_uio function is a variation of .Nm sglist_append_uio . @@ -421,7 +450,9 @@ functions return zero on success or an e .Pp The .Nm sglist_count -function returns a count of scatter/gather list elements. +and +.Nm sglist_count_vmpages +functions return a count of scatter/gather list elements. .Pp The .Nm sglist_length Modified: head/sys/kern/subr_sglist.c ============================================================================== --- head/sys/kern/subr_sglist.c Fri May 20 23:08:22 2016 (r300336) +++ head/sys/kern/subr_sglist.c Fri May 20 23:28:43 2016 (r300337) @@ -192,6 +192,31 @@ sglist_count(void *buf, size_t len) } /* + * Determine the number of scatter/gather list elements needed to + * describe a buffer backed by an array of VM pages. + */ +int +sglist_count_vmpages(vm_page_t *m, size_t pgoff, size_t len) +{ + vm_paddr_t lastaddr, paddr; + int i, nsegs; + + if (len == 0) + return (0); + + len += pgoff; + nsegs = 1; + lastaddr = VM_PAGE_TO_PHYS(m[0]); + for (i = 1; len > PAGE_SIZE; len -= PAGE_SIZE, i++) { + paddr = VM_PAGE_TO_PHYS(m[i]); + if (lastaddr + PAGE_SIZE != paddr) + nsegs++; + lastaddr = paddr; + } + return (nsegs); +} + +/* * Allocate a scatter/gather list along with 'nsegs' segments. The * 'mflags' parameters are the same as passed to malloc(9). The caller * should use sglist_free() to free this list. @@ -252,33 +277,14 @@ sglist_append(struct sglist *sg, void *b int sglist_append_bio(struct sglist *sg, struct bio *bp) { - struct sgsave save; - vm_paddr_t paddr; - size_t len, tlen; - int error, i, ma_offs; + int error; - if ((bp->bio_flags & BIO_UNMAPPED) == 0) { + if ((bp->bio_flags & BIO_UNMAPPED) == 0) error = sglist_append(sg, bp->bio_data, bp->bio_bcount); - return (error); - } - - if (sg->sg_maxseg == 0) - return (EINVAL); - - SGLIST_SAVE(sg, save); - tlen = bp->bio_bcount; - ma_offs = bp->bio_ma_offset; - for (i = 0; tlen > 0; i++, tlen -= len) { - len = min(PAGE_SIZE - ma_offs, tlen); - paddr = VM_PAGE_TO_PHYS(bp->bio_ma[i]) + ma_offs; - error = sglist_append_phys(sg, paddr, len); - if (error) { - SGLIST_RESTORE(sg, save); - return (error); - } - ma_offs = 0; - } - return (0); + else + error = sglist_append_vmpages(sg, bp->bio_ma, + bp->bio_ma_offset, bp->bio_bcount); + return (error); } /* @@ -341,6 +347,51 @@ sglist_append_mbuf(struct sglist *sg, st } /* + * Append the segments that describe a buffer spanning an array of VM + * pages. The buffer begins at an offset of 'pgoff' in the first + * page. + */ +int +sglist_append_vmpages(struct sglist *sg, vm_page_t *m, size_t pgoff, + size_t len) +{ + struct sgsave save; + struct sglist_seg *ss; + vm_paddr_t paddr; + size_t seglen; + int error, i; + + if (sg->sg_maxseg == 0) + return (EINVAL); + if (len == 0) + return (0); + + SGLIST_SAVE(sg, save); + i = 0; + if (sg->sg_nseg == 0) { + seglen = min(PAGE_SIZE - pgoff, len); + sg->sg_segs[0].ss_paddr = VM_PAGE_TO_PHYS(m[0]) + pgoff; + sg->sg_segs[0].ss_len = seglen; + sg->sg_nseg = 1; + pgoff = 0; + len -= seglen; + i++; + } + ss = &sg->sg_segs[sg->sg_nseg - 1]; + for (; len > 0; i++, len -= seglen) { + seglen = min(PAGE_SIZE - pgoff, len); + paddr = VM_PAGE_TO_PHYS(m[i]) + pgoff; + error = _sglist_append_range(sg, &ss, paddr, seglen); + if (error) { + SGLIST_RESTORE(sg, save); + return (error); + } + pgoff = 0; + } + return (0); +} + +/* * Append the segments that describe a single user address range to a * scatter/gather list. If there are insufficient segments, then this * fails with EFBIG. Modified: head/sys/sys/sglist.h ============================================================================== --- head/sys/sys/sglist.h Fri May 20 23:08:22 2016 (r300336) +++ head/sys/sys/sglist.h Fri May 20 23:28:43 2016 (r300337) @@ -91,10 +91,13 @@ int sglist_append_phys(struct sglist *sg 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); +int sglist_append_vmpages(struct sglist *sg, vm_page_t *m, size_t pgoff, + size_t len); 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, size_t resid); int sglist_count(void *buf, size_t len); +int sglist_count_vmpages(vm_page_t *m, size_t pgoff, 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);