svn commit: r300337 - in head: share/man/man9 sys/kern sys/sys

John Baldwin jhb at FreeBSD.org
Fri May 20 23:28:44 UTC 2016


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);


More information about the svn-src-all mailing list