SGLIST(9)
okay so bestie, this is the SGLIST(9) page from the Kernel Developer's Manual, and it's basically the group chat for managing a scatter/gather list of physical memory addresses. The whole squad is: sglist, sglist_alloc, sglist_append, sglist_append_bio, sglist_append_mbuf, sglist_append_mbuf_epg, sglist_append_phys, sglist_append_sglist, sglist_append_single_mbuf, sglist_append_uio, sglist_append_user, sglist_append_vmpages, sglist_build, sglist_clone, sglist_consume_uio, sglist_count, sglist_count_mbuf_epg, sglist_count_vmpages, sglist_free, sglist_hold, sglist_init, sglist_join, sglist_length, sglist_reset, sglist_slice, and sglist_split β and they all manage a scatter/gather list of physical memory addresses. iconic behavior, honestly.
β¨ SYNOPSIS β¨
here are the exact signatures, no cap β copy them character for character:
#include <sys/types.h>
#include <sys/sglist.h>
struct sglist *
sglist_alloc(int nsegs, int mflags);
int
sglist_append(struct sglist *sg, void *buf, size_t len);
int
sglist_append_bio(struct sglist *sg, struct bio *bp);
int
sglist_append_mbuf_epg(struct sglist *sg, struct mbuf *m, size_t offset,
size_t len);
int
sglist_append_mbuf(struct sglist *sg, struct mbuf *m);
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 len);
int
sglist_append_single_mbuf(struct sglist *sg, struct mbuf *m);
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_mbuf_epg(struct mbuf *m, size_t offset, size_t len);
int
sglist_count_vmpages(vm_page_t *m, size_t pgoff, size_t len);
void
sglist_free(struct sglist *sg);
struct sglist *
sglist_hold(struct sglist *sg);
void
sglist_init(struct sglist *sg, int maxsegs, struct sglist_seg *segs);
int
sglist_join(struct sglist *first, struct sglist *second);
size_t
sglist_length(struct sglist *sg);
void
sglist_reset(struct sglist *sg);
int
sglist_slice(struct sglist *original, struct sglist **slice,
size_t offset, size_t length, int mflags);
int
sglist_split(struct sglist *original, struct sglist **head,
size_t length, int mflags);
π DESCRIPTION π
okay so bestie, the sglist API is literally all about managing physical address ranges. Each list has one or more elements, and every element is just a starting physical address plus a length. That's the whole vibe.
Scatter/gather lists are read-only while they are shared. If you wanna alter an existing scatter/gather list and you don't hold the sole reference to it, do not modify it β create a new list instead. no cap.
Every scatter/gather list object has a reference count. New lists are created with a single reference. You grab new references with sglist_hold and release them with sglist_free. π«Ά
β¨ Allocating and Initializing Lists β¨
Each sglist object is a header structure plus a variable-length array of scatter/gather list elements. iconic.
sglist_allocβ allocates a new list with a header andnsegsscatter/gather list elements. Themflagsargument can be set to eitherM_NOWAITorM_WAITOK.sglist_countβ returns the number of scatter/gather list elements needed to describe the physical address ranges mapped by a single kernel virtual address range. That range starts atbufand islenbytes long.sglist_count_mbuf_epgβ returns the number of scatter/gather list elements needed to describe the external multipage mbuf bufferm. The ranges start at an offset ofoffsetrelative to the start of the buffer and arelenbytes long.sglist_count_vmpagesβ 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 pagesm. The buffer starts at an offset ofpgoffbytes relative to the first page and islenbytes long.sglist_buildβ allocates a new scatter/gather list object that describes the physical address ranges mapped by a single kernel virtual address range. The range starts atbufand islenbytes long. Themflagsargument can be set to eitherM_NOWAITorM_WAITOK.sglist_cloneβ returns a copy of an existing scatter/gather list objectsg. Themflagsargument can be set to eitherM_NOWAITorM_WAITOK. This is how you get a private copy before modifying it. πsglist_initβ initializes a scatter/gather list header. The header is pointed to bysgand is initialized to manage an array ofmaxsegsscatter/gather list elements pointed to bysegs.
sglist_init is the move when the header storage wasn't provided by sglist_alloc. In that case, the caller should not call sglist_free to release its own reference, and the caller is responsible for making sure all other references to the list are dropped before it releases the storage for sg and segs. don't forget that part, bestie π
π§ Constructing Scatter/Gather Lists π§
The sglist API gives you a whole little family of routines for building a scatter/gather list that describes one or more objects. Specifically, the sglist_append family appends the physical address ranges described by an object to the end of a scatter/gather list.
All of these routines return 0 on success or an error on failure. And if a request to append an address range to a scatter/gather list fails, the scatter/gather list will remain unchanged. slay.
sglist_appendβ appends the physical address ranges described by a single kernel virtual address range to the scatter/gather listsg. The range starts atbufand islenbytes long.sglist_append_bioβ appends the physical address ranges described by a single biobpto the scatter/gather listsg.sglist_append_mbuf_epgβ appends the physical address ranges described by the external multipagembuf(9)bufferext_pgsto the scatter/gather listsg. The physical address ranges start at offsetoffsetwithinext_pgsand continue forlenbytes. Note that unlikesglist_append_mbuf,sglist_append_mbuf_epgonly adds ranges for a single mbuf, not an entire mbuf chain.sglist_append_mbufβ appends the physical address ranges described by an entire mbuf chainmto the scatter/gather listsg.sglist_append_single_mbufβ appends the physical address ranges described by a single mbufmto the scatter/gather listsg.sglist_append_physβ appends a single physical address range to the scatter/gather listsg. The physical address range starts atpaddrand islenbytes long.sglist_append_sglistβ appends physical address ranges described by the scatter/gather listsourceto the scatter/gather listsg. The physical address ranges start at offsetoffsetwithinsourceand continue forlenbytes.sglist_append_uioβ appends the physical address ranges described by auio(9)object to the scatter/gather listsg. It is the caller's responsibility to ensure that the pages backing the I/O request are wired for the lifetime ofsg. Also note that this routine does not modifyuio.sglist_append_userβ appends the physical address ranges described by a single user virtual address range to the scatter/gather listsg. The user virtual address range is relative to the address space of the threadtd. It starts atbufand islenbytes long. It is the caller's responsibility to ensure that the pages backing the user buffer are wired for the lifetime ofsg.sglist_append_vmpagesβ appends the physical address ranges of a buffer backed by an array of virtual memory pagesm. The buffer starts at an offset ofpgoffbytes relative to the first page and islenbytes long.sglist_consume_uioβ a variation ofsglist_append_uio. Likesglist_append_uio, it appends the physical address ranges described byuioto the scatter/gather listsg. Unlikesglist_append_uio, though,sglist_consume_uiomodifies the I/O request to indicate that the appended address ranges have been processed, similar to callinguiomove(9). This routine will only append ranges that describe up toresidtotal bytes in length. If the available segments in the scatter/gather list are exhausted beforeresidbytes are processed, then theuiostructure will be updated to reflect the actual number of bytes processed, andsglist_consume_iowill return zero to indicate success. In effect, this function will perform partial reads or writes. The caller can compare theuio_residmember ofuiobefore and after callingsglist_consume_uioto determine the actual number of bytes processed. π₯
π Manipulating Scatter/Gather Lists π
sglist_joinβ appends physical address ranges from the scatter/gather listsecondontofirstand then resetssecondto an empty list. It returns zero on success or an error on failure.sglist_splitβ splits an existing scatter/gather list into two lists. The firstlengthbytes described by the listoriginalare moved to a new list*head. Iforiginaldescribes a total address range that is smaller thanlengthbytes, then all of the address ranges will be moved to the new list at*headandoriginalwill be an empty list.
The caller may supply an existing scatter/gather list in *head. If so, the list must be empty. Otherwise, the caller may set *head to NULL, in which case a new scatter/gather list will be allocated. In that case, mflags may be set to either M_NOWAIT or M_WAITOK.
Note that since the original list is modified by this call, it must be a private list with no other references. The sglist_split function returns zero on success or an error on failure.
sglist_sliceβ generates a new scatter/gather list from a sub-range of an existing scatter/gather listoriginal. The sub-range to extract is specified by theoffsetandlengthparameters. The new scatter/gather list is stored in*slice.
As with head for sglist_join, the caller may either provide an empty scatter/gather list, or it may set *slice to NULL, in which case sglist_slice will allocate a new list subject to mflags.
Unlike sglist_split, sglist_slice does not modify original and does not require it to be a private list. The sglist_split function returns zero on success or an error on failure. π¦
πΈ Miscellaneous Routines πΈ
sglist_resetβ clears the scatter/gather listsgso that it no longer maps any address ranges. This can allow reuse of a single scatter/gather list object for multiple requests.sglist_lengthβ returns the total length of the physical address ranges described by the scatter/gather listsg.
β RETURN VALUES β
- The
sglist_alloc,sglist_build, andsglist_clonefunctions return a new scatter/gather list on success orNULLon failure. - The
sglist_appendfamily of functions and thesglist_consume_uio,sglist_join,sglist_slice, andsglist_splitfunctions return zero on success or an error on failure. - The
sglist_countfamily of functions return a count of scatter/gather list elements. - The
sglist_lengthfunction returns a count of address space described by a scatter/gather list in bytes.
π ERRORS π
ok so when things go sideways, these are the errno values that come back at you. bestie, memorize them, they will show up.
π«Ά the sglist_append girlies
The sglist_append functions return the following errors on failure:
[EINVAL]β the scatter/gather list straight up has zero segments. empty. nothing. nada.[EFBIG]β there aren't enough available segments left in the scatter/gather list to append all the physical address ranges you asked for. ran out of room, tragic.
πΈ sglist_consume_uio
The sglist_consume_uio function returns the following error on failure:
[EINVAL]β again, the scatter/gather list has zero segments. she's empty, she can't consume anything.
π sglist_join
The sglist_join function returns the following error on failure:
[EFBIG]β there are not enough available segments in the scatter/gather list first to append the physical address ranges from second. like trying to merge two friend groups into a venue that's already at capacity π
π sglist_slice
The sglist_slice function returns the following errors on failure:
[EINVAL]β the original scatter/gather list does not describe enough address space to cover the requested sub-range. you asked for a slice that doesn't exist, bestie.[EINVAL]β the caller-supplied scatter/gather list in*sliceis not empty. it has to be empty before you hand it over, that's the rule.[ENOMEM]β an attempt to allocate a new scatter/gather list withM_NOWAITset inmflagsfailed. the malloc said no π[EFBIG]β there are not enough available segments in the caller-supplied scatter/gather list in*sliceto describe the requested physical address ranges.
β sglist_split
The sglist_split function returns the following errors on failure:
[EDOOFUS]β the original scatter/gather list has more than one reference. yes, that's really the name, and yes it's iconic β it literally means "you did something dumb" π[EINVAL]β the caller-supplied scatter/gather list in*headis not empty. same vibe as above: empty it first.[ENOMEM]β an attempt to allocate a new scatter/gather list withM_NOWAITset inmflagsfailed. again, malloc said no.[EFBIG]β there are not enough available segments in the caller-supplied scatter/gather list in*headto describe the requested physical address ranges.
π SEE ALSO π
go read these next, they're the whole friend group:
π¦ HISTORY π¦
This API was first introduced in FreeBSD 8.0. she's been around a minute, lowkey a legend.
and that's the whole page, bestie! π this rendition came to you via Debian, dated May 25, 2021 β so like, keep that in mind when you're citing it. now go forth and manage your scatter/gather lists responsibly β¨π
π¦ where this page comes from
- freebsd 15.1: base 15.1
- nixpkgs unstable: source
- Copyright (c) 2009 Hudson River Trading LLC
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms