Add sglist_append_sglist().

This function permits a range of one scatter/gather list to be appended to
another sglist.  This can be used to construct a scatter/gather list that
reorders or duplicates ranges from one or more existing scatter/gather
lists.

Sponsored by:	Chelsio Communications
This commit is contained in:
John Baldwin 2017-05-16 23:31:52 +00:00
parent 720e7bb69c
commit 00f6cd3f56
4 changed files with 64 additions and 1 deletions

View File

@ -1572,6 +1572,7 @@ MLINKS+=sglist.9 sglist_alloc.9 \
sglist.9 sglist_append_bio.9 \
sglist.9 sglist_append_mbuf.9 \
sglist.9 sglist_append_phys.9 \
sglist.9 sglist_append_sglist.9 \
sglist.9 sglist_append_uio.9 \
sglist.9 sglist_append_user.9 \
sglist.9 sglist_append_vmpages.9 \

View File

@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd January 12, 2014
.Dd May 16, 2017
.Dt SGLIST 9
.Os
.Sh NAME
@ -36,6 +36,7 @@
.Nm sglist_append_bio ,
.Nm sglist_append_mbuf ,
.Nm sglist_append_phys ,
.Nm sglist_append_sglist ,
.Nm sglist_append_uio ,
.Nm sglist_append_user ,
.Nm sglist_append_vmpages ,
@ -67,6 +68,8 @@
.Ft int
.Fn sglist_append_phys "struct sglist *sg" "vm_paddr_t paddr" "size_t len"
.Ft int
.Fn sglist_append_sglist "struct sglist *sg" "struct sglist *source" "size_t offset" "size_t len"
.Ft int
.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"
@ -252,6 +255,20 @@ and is
bytes long.
.Pp
The
.Nm sglist_append_sglist
function appends physical address ranges described by the scatter/gather list
.Fa source
to the scatter/gather list
.Fa sg .
The physical address ranges start at offset
.Fa offset
within
.Fa source
and continue for
.Fa len
bytes.
.Pp
The
.Nm sglist_append_uio
function appends the physical address ranges described by a
.Xr uio 9

View File

@ -412,6 +412,49 @@ sglist_append_user(struct sglist *sg, void *buf, size_t len, struct thread *td)
return (error);
}
/*
* Append a subset of an existing scatter/gather list 'source' to a
* the scatter/gather list 'sg'. If there are insufficient segments,
* then this fails with EFBIG.
*/
int
sglist_append_sglist(struct sglist *sg, struct sglist *source, size_t offset,
size_t length)
{
struct sgsave save;
struct sglist_seg *ss;
size_t seglen;
int error, i;
if (sg->sg_maxseg == 0 || length == 0)
return (EINVAL);
SGLIST_SAVE(sg, save);
error = EINVAL;
ss = &sg->sg_segs[sg->sg_nseg - 1];
for (i = 0; i < source->sg_nseg; i++) {
if (offset >= source->sg_segs[i].ss_len) {
offset -= source->sg_segs[i].ss_len;
continue;
}
seglen = source->sg_segs[i].ss_len - offset;
if (seglen > length)
seglen = length;
error = _sglist_append_range(sg, &ss,
source->sg_segs[i].ss_paddr + offset, seglen);
if (error)
break;
offset = 0;
length -= seglen;
if (length == 0)
break;
}
if (length != 0)
error = EINVAL;
if (error)
SGLIST_RESTORE(sg, save);
return (error);
}
/*
* Append the segments that describe a single uio to a scatter/gather
* list. If there are insufficient segments, then this fails with

View File

@ -88,6 +88,8 @@ int sglist_append_bio(struct sglist *sg, struct bio *bp);
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_sglist(struct sglist *sg, struct sglist *source,
size_t offset, size_t length);
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);