Index: sys/conf/files =================================================================== RCS file: /cvs/src/sys/conf/files,v retrieving revision 1.575 diff -u -p -r1.575 files --- sys/conf/files 13 Jul 2014 15:32:28 -0000 1.575 +++ sys/conf/files 14 Aug 2014 09:16:54 -0000 @@ -706,6 +706,7 @@ file kern/subr_evcount.c file kern/subr_extent.c file kern/subr_hibernate.c hibernate file kern/subr_log.c +file kern/subr_mbuf.c file kern/subr_poison.c diagnostic file kern/subr_pool.c file kern/dma_alloc.c Index: sys/kern/subr_mbuf.c =================================================================== RCS file: sys/kern/subr_mbuf.c diff -N sys/kern/subr_mbuf.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/kern/subr_mbuf.c 14 Aug 2014 09:16:54 -0000 @@ -0,0 +1,171 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2014 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include + +void ml_join(struct mbuf_list *, struct mbuf_list *); + +/* + * mbuf lists + */ + +void +ml_init(struct mbuf_list *ml) +{ + ml->ml_head = ml->ml_tail = NULL; + ml->ml_len = 0; +} + +void +ml_enqueue(struct mbuf_list *ml, struct mbuf *m) +{ + if (ml->ml_tail == NULL) + ml->ml_head = ml->ml_tail = m; + else { + ml->ml_tail->m_nextpkt = m; + ml->ml_tail = m; + } + + m->m_nextpkt = NULL; + ml->ml_len++; +} + +void +ml_join(struct mbuf_list *mla, struct mbuf_list *mlb) +{ + if (mla->ml_tail == NULL) + *mla = *mlb; + else if (mlb->ml_tail != NULL) { + mla->ml_tail->m_nextpkt = mlb->ml_head; + mla->ml_tail = mlb->ml_tail; + mla->ml_len += mlb->ml_len; + + ml_init(mlb); + } +} + +struct mbuf * +ml_dequeue(struct mbuf_list *ml) +{ + struct mbuf *m; + + m = ml->ml_head; + if (m != NULL) { + ml->ml_head = m->m_nextpkt; + if (ml->ml_head == NULL) + ml->ml_tail = NULL; + + m->m_nextpkt = NULL; + ml->ml_len--; + } + + return (m); +} + +struct mbuf * +ml_dechain(struct mbuf_list *ml) +{ + struct mbuf *m0; + + m0 = ml->ml_head; + + ml_init(ml); + + return (m0); +} + +/* + * mbuf queues + */ + +void +mq_init(struct mbuf_queue *mq, u_int maxlen, int ipl) +{ + mtx_init(&mq->mq_mtx, ipl); + ml_init(&mq->mq_list); + mq->mq_maxlen = maxlen; +} + +int +mq_enqueue(struct mbuf_queue *mq, struct mbuf *m) +{ + int dropped = 0; + + mtx_enter(&mq->mq_mtx); + if (mq_len(mq) < mq->mq_maxlen) + ml_enqueue(&mq->mq_list, m); + else { + mq->mq_drops++; + dropped = 1; + } + mtx_leave(&mq->mq_mtx); + + if (dropped) + m_freem(m); + + return (dropped); +} + +struct mbuf * +mq_dequeue(struct mbuf_queue *mq) +{ + struct mbuf *m; + + mtx_enter(&mq->mq_mtx); + m = ml_dequeue(&mq->mq_list); + mtx_leave(&mq->mq_mtx); + + return (m); +} + +int +mq_enlist(struct mbuf_queue *mq, struct mbuf_list *ml) +{ + int full; + + mtx_enter(&mq->mq_mtx); + ml_join(&mq->mq_list, ml); + full = mq_len(mq) >= mq->mq_maxlen; + mtx_leave(&mq->mq_mtx); + + return (full); +} + +void +mq_delist(struct mbuf_queue *mq, struct mbuf_list *ml) +{ + mtx_enter(&mq->mq_mtx); + *ml = mq->mq_list; + ml_init(&mq->mq_list); + mtx_leave(&mq->mq_mtx); +} + +struct mbuf * +mq_dechain(struct mbuf_queue *mq) +{ + struct mbuf *m0; + + mtx_enter(&mq->mq_mtx); + m0 = ml_dechain(&mq->mq_list); + mtx_leave(&mq->mq_mtx); + + return (m0); +} Index: sys/sys/mbuf_list.h =================================================================== RCS file: sys/sys/mbuf_list.h diff -N sys/sys/mbuf_list.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/sys/mbuf_list.h 14 Aug 2014 09:16:54 -0000 @@ -0,0 +1,77 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2014 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SYS_MBUF_LIST_H_ +#define _SYS_MBUF_LIST_H_ + +#include +#include + +#ifdef _KERNEL + +/* + * mbuf lists + */ + +struct mbuf_list { + struct mbuf *ml_head; + struct mbuf *ml_tail; + u_int ml_len; +}; + +#define MBUF_LIST_INITIALIZER() { NULL, NULL, 0 } + +void ml_init(struct mbuf_list *); +void ml_enqueue(struct mbuf_list *, struct mbuf *); +struct mbuf * ml_dequeue(struct mbuf_list *); +struct mbuf * ml_dechain(struct mbuf_list *); + +#define ml_len(_ml) ((_ml)->ml_len) +#define ml_empty(_ml) ((_ml)->ml_len == 0) + +#define MBUF_LIST_FOREACH(_ml, _m) \ + for ((_m) = (_ml)->ml_head; (_m) != NULL; (_m) = (_m)->m_nextpkt) + +/* + * mbuf queues + */ + +struct mbuf_queue { + struct mutex mq_mtx; + struct mbuf_list mq_list; + u_int mq_maxlen; + u_int mq_drops; +}; + +#define MBUF_QUEUE_INITIALIZER(_maxlen, _ipl) \ + { MUTEX_INITIALIZER(_ipl), MBUF_LIST_INITIALIZER(), (_maxlen), 0 } + +void mq_init(struct mbuf_queue *, u_int, int); +int mq_enqueue(struct mbuf_queue *, struct mbuf *); +struct mbuf * mq_dequeue(struct mbuf_queue *); +int mq_enlist(struct mbuf_queue *, struct mbuf_list *); +void mq_delist(struct mbuf_queue *, struct mbuf_list *); +struct mbuf * mq_dechain(struct mbuf_queue *); + +#define mq_len(_mq) ml_len(&(_mq)->mq_list) +#define mq_empty(_mq) ml_empty(&(_mq)->mq_list) +#define mq_drops(_mq) ((_mq)->mq_drops) +#define mq_set_maxlen(_mq, _l) ((_mq)->mq_maxlen = (_l)) + +#endif /* _KERNEL */ +#endif /* _SYS_MBUF_LIST_H_ */ Index: share/man/man9/Makefile =================================================================== RCS file: /cvs/src/share/man/man9/Makefile,v retrieving revision 1.218 diff -u -p -r1.218 Makefile --- share/man/man9/Makefile 24 Jul 2014 01:18:23 -0000 1.218 +++ share/man/man9/Makefile 14 Aug 2014 09:16:54 -0000 @@ -22,7 +22,7 @@ MAN= aml_evalnode.9 atomic_add_int.9 ato kern.9 km_alloc.9 knote.9 kthread.9 ktrace.9 \ loadfirmware.9 lock.9 log.9 \ malloc.9 membar_sync.9 mbuf.9 mbuf_tags.9 md5.9 mi_switch.9 \ - microtime.9 mountroothook_establish.9 mutex.9 namei.9 \ + microtime.9 ml_init.9 mountroothook_establish.9 mutex.9 namei.9 \ panic.9 pci_conf_read.9 pci_intr_map.9 pfind.9 physio.9 pmap.9 \ pool.9 powerhook_establish.9 ppsratecheck.9 printf.9 psignal.9 \ radio.9 arc4random.9 rasops.9 ratecheck.9 resettodr.9 rssadapt.9 \ @@ -267,6 +267,14 @@ MLINKS+=microtime.9 getmicrotime.9 micro microtime.9 getnanotime.9 microtime.9 nanouptime.9 \ microtime.9 getnanouptime.9 microtime.9 bintime.9 \ microtime.9 binuptime.9 +MLINKS+=ml_init.9 ml_enqueue.9 ml_init.9 ml_dequeue.9 ml_init.9 ml_dechain.9 \ + ml_init.9 ml_len.9 ml_init.9 ml_empty.9 \ + ml_init.9 MBUF_LIST_INITIALIZER.9 ml_init.9 MBUF_LIST_FOREACH.9 \ + ml_init.9 mq_enqueue.9 ml_init.9 mq_dequeue.9 ml_init.9 mq_enlist.9 \ + ml_init.9 mq_delist.9 ml_init.9 mq_dechain.9 \ + ml_init.9 mq_len.9 ml_init.9 mq_empty.9 \ + ml_init.9 mq_drops.9 ml_init.9 mq_set_maxlen.9 \ + ml_init.9 MBUF_QUEUE_INITIALIZER.9 MLINKS+=mountroothook_establish.9 mountroothook_disestablish.9 MLINKS+=mutex.9 mtx_init.9 mutex.9 mtx_enter.9 mutex.9 mtx_leave.9 \ mutex.9 MUTEX_ASSERT_LOCKED.9 mutex.9 MUTEX_ASSERT_UNLOCKED.9 \ Index: share/man/man9/ml_init.9 =================================================================== RCS file: share/man/man9/ml_init.9 diff -N share/man/man9/ml_init.9 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ share/man/man9/ml_init.9 14 Aug 2014 09:16:54 -0000 @@ -0,0 +1,293 @@ +.\" $OpenBSD$ +.\" +.\" Copyright (c) 2014 David Gwynne +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: June 19 2014 $ +.Dt ML_INIT 9 +.Os +.Sh NAME +.Nm ml_init , +.Nm ml_enqueue , +.Nm ml_dequeue , +.Nm ml_dechain , +.Nm ml_len , +.Nm ml_empty , +.Nm MBUF_LIST_INITIALIZER , +.Nm MBUF_LIST_FOREACH , +.Nm mq_init , +.Nm mq_enqueue , +.Nm mq_dequeue , +.Nm mq_enlist , +.Nm mq_delist , +.Nm mq_dechain , +.Nm mq_len , +.Nm mq_empty , +.Nm mq_drops , +.Nm mq_set_maxlen , +.Nm MBUF_QUEUE_INITIALIZER +.Nd mbuf lists and queues +.Sh SYNOPSIS +.In sys/mbuf.h +.In sys/mbuf_init.h +.Ft void +.Fn "ml_init" "struct mbuf_list *ml" +.Ft void +.Fn "ml_enqueue" "struct mbuf_list *ml" "struct mbuf *m" +.Ft struct mbuf * +.Fn "ml_dequeue" "struct mbuf_list *ml" +.Ft struct mbuf * +.Fn "ml_dechain" "struct mbuf_list *ml" +.Ft unsigned int +.Fn "ml_len" "struct mbuf_list *ml" +.Ft int +.Fn "ml_empty" "struct mbuf_list *ml" +.Ft struct mbuf_list +.Fn "MBUF_LIST_INITIALIZER" +.Fn "MBUF_LIST_FOREACH" "struct mbuf_list *ml" "VARNAME" +.Fn "mq_init" "struct mbuf_queue *mq" "unsigned int maxlen" "int ipl" +.Ft int +.Fn "mq_enqueue" "struct mbuf_queue *mq" "struct mbuf *m" +.Ft struct mbuf * +.Fn "mq_dequeue" "struct mbuf_queue *mq" +.Ft int +.Fn "mq_enlist" "struct mbuf_queue *mq" "struct mbuf_list *ml" +.Ft void +.Fn "mq_delist" "struct mbuf_queue *mq "struct mbuf_list *ml" +.Ft struct mbuf * +.Fn "mq_dechain" "struct mbuf_queue *mq" +.Ft unsigned int +.Fn "mq_len" "struct mbuf_queue *mq" +.Ft int +.Fn "mq_empty" "struct mbuf_queue *mq" +.Ft unsigned int +.Fn "mq_drops" "struct mbuf_queue *mq" +.Ft void +.Fn "mq_set_maxlen" "struct mbuf_queue *mq" "unsigned int" +.Ft struct mbuf_queue +.Fn "MBUF_QUEUE_INITIALIZER" "unsigned int maxlen" "int ipl" +.Sh DESCRIPTION +The mbuf list and mbuf queue API provides implementions of data +structures and operations for managing lists of mbufs or for queueing +mbufs and lists of mbufs between contexts. +.Pp +mbuf_list structures support the following functionality: +.Pp +.Bl -enum -compact -offset indent +.It +Insertion of a new mbuf at the end of the list. +.It +Removal of an mbuf from the head of the list. +.It +Removal of the entire chain of mbufs on the list. +.El +.Pp +An mbuf_list structure can be initialised with +.Fn ml_init +when passed as a pointer via +.Fa ml . +An mbuf_list declaration can be statically initialised with the +.Fn MBUF_LIST_INITIALIZER +macro. +.Pp +The +.Fn ml_enqueue +function inserts the mbuf +.Fa m +at the end of the mbuf list +.Fa ml . +.Pp +.Fn ml_dequeue +removes the first mbuf in the list pointed by +.Fa ml . +.Pp +.Fn ml_dechain +removes the entire list of mbufs in the list pointed to by +.Fa ml . +.Pp +.Fn ml_len +can be used to find out the total number of mbufs in the list pointed to by +.Fa ml . +.Pp +.Fn ml_empty +can be used to determine if the mbuf list pointed to by +.Fa ml +is empty. +.Pp +.Fn MBUF_LIST_FOREACH +is a convenience macro that can be used to iterate over the contents of the list specified by +.Fa ml . +.Fa VARNAME +identifies the name (not the address) of an mbuf pointer that will +be set to each entry on the list. +Note that it is unsafe to modify the list while iterating over it. +.Pp +mbuf_queue data structures provide a superset of the functionality +available in mbuf_lists, and protect themselves internally with a +.Xr mutex 9 , +making them useful for moving mbufs between contexts or subsystems. +Additionally, mbuf_queues provide a limit on the number of mbufs that +may be queued. +The additional functionality mbuf_queues provides is: +.Pp +.Bl -enum -compact -offset indent +.It +Insertion of the mbufs in an mbuf_list at the end of the queue. +.It +Removal of all the mbufs on the queue as an mbuf_list. +.El +.Pp +An mbuf_queue structure can be initialised with +.Fn mq_init +when passed as the +.Fa mq +argument. +An mbuf_queue declaration may be statically initialised with the +.Fn MBUF_QUEUE_INITIALIZER +macro. +Both +.Fn mq_init +and +.Fn MBUF_QUEUE_INITIALIZSER +take the interrupt priority level its internal +.Xr mutex 9 +is initialised with via the +.Fa ipl +argument, +and the maximum number of mbufs that should be on the queue via +.Fa maxlen . +.Pp +.Fn mq_enqueue +inserts the mbuf +.Fa m +at the end of the mbuf queue +.Fa mq . +If the number of mbufs already on the list exceeds the queues maximum length, +the mbuf is freed with +.Xr m_freem 9 . +.Pp +.Fn mq_dequeue +removes the first mbuf in the queue pointed by +.Fa mq . +.Pp +.Fn mq_enlist +inserts the mbufs in the list +.Fa ml +at the end of the mbuf queue +.Fa mq . +Note, if the number of mbufs placed on the queue exceeds its maxumum length, +the extra mbufs are NOT freed as they are with +.Fn mq_enqueue . +.Pp +.Fn mq_delist +moves all the mbufs on the queue +.Fa mq +to the list +.Fa ml . +.Pp +.Fn mq_dechain +removes all the mbufs in the queue pointed to by +.Fa mq . +.Pp +.Fn mq_len +can be used to find out the total number of mbufs in the queue pointed to by +.Fa mq . +.Pp +.Fn mq_empty +can be used to determine if the mbuf queue pointed to by +.Fa mq +is empty. +.Pp +.Fn mq_drops +can be used to determine how many mbufs were dropped and freed by +.Xr m_freem 9 +if the mbuf queue pointed to by +.Fa mq +was too full. +.Pp +.Fn mq_set_maxlen +can be used to alter the maximum number of mbufs that can be queued on +.Fa mq . +.Fn mq_set_maxlen +will only set a new limit, it will not free any excess mbufs already that may +already exist on the queue. +.Sh CONTEXT +.Fn ml_init , +.Fn ml_enqueue , +.Fn ml_dequeue , +.Fn ml_dechain , +.Fn ml_len , +.Fn ml_empty , +.Fn MBUF_LIST_INITIALIZER , +.Fn mq_init , +.Fn mq_enqueue , +.Fn mq_dequeue , +.Fn mq_enlist , +.Fn mq_delist , +.Fn mq_dechain , +.Fn mq_len , +.Fn mq_empty , +.Fn mq_drops , +.Fn mq_set_maxlen , +.Fn MBUF_QUEUE_INITIALIZER +can be called during autoconf, from process context, or from interrupt context. +.Sh RETURN VALUES +.Fn ml_dequeue +and +.Fn mq_dequeue +return the mbuf that was at the head of their respective list or queue. +If the list or queue was empty, +.Dv NULL +is returned. +.Pp +.Fn ml_dechain +and +.Fn mq_dechain +returns all the mbufs that were on the respective list or queues via +a pointer to an mbuf with the chain accessible via m_nextpkt members. +If the list or queue was empty, +.Dv NULL +is returned. +.Pp +.Fn ml_len +and +.Fn mq_len +return the number of mbufs on the list or queue respectively. +.Pp +.Fn ml_empty +and +.Fn mq_empty +return a non-zero value if the list or queue is empty, +otherwise 0. +.Pp +.Fn mq_enqueue +returns 0 if the mbuf was successfully queued, or non-zero if the +mbuf was freed because it would cause the queue to exceed its maximum +length. +.Pp +.Fn mq_enlist +returns 0 if the new length of the queue after adding the list is less than the queues maximum length, otherwise non-zero. +.Pp +.Fn mq_drops +returns the number of mbufs that were freed during +.Fn mq_enqueue +operations that would have caused the queue to exceed its maximum length. +.Sh SEE ALSO +.Xr mbuf 9 , +.Xr spl 9 +.Sh HISTORY +The mbuf list and queue API was originally written by +.An David Gwynne Aq Mt dlg@openbsd.org . +The mbuf list and queue API first appeared in +.Ox 5.7 .