diff options
author | John Baldwin <jhb@FreeBSD.org> | 2017-05-16 23:31:52 +0000 |
---|---|---|
committer | John Baldwin <jhb@FreeBSD.org> | 2017-05-16 23:31:52 +0000 |
commit | 00f6cd3f568295e501deae63e38b34d1137a6eb9 (patch) | |
tree | b5418f224fa5ccfc97075346fef722159b3a951f /sys/kern/subr_sglist.c | |
parent | 720e7bb69c26b445287b7dd12d2f1e709b227953 (diff) | |
download | src-test2-00f6cd3f568295e501deae63e38b34d1137a6eb9.tar.gz src-test2-00f6cd3f568295e501deae63e38b34d1137a6eb9.zip |
Notes
Diffstat (limited to 'sys/kern/subr_sglist.c')
-rw-r--r-- | sys/kern/subr_sglist.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/sys/kern/subr_sglist.c b/sys/kern/subr_sglist.c index 0d371a48ded3..dbc2a5e72fee 100644 --- a/sys/kern/subr_sglist.c +++ b/sys/kern/subr_sglist.c @@ -413,6 +413,49 @@ sglist_append_user(struct sglist *sg, void *buf, size_t len, struct thread *td) } /* + * 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 * EFBIG. |