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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to