xref: /dragonfly/sys/kern/kern_mpipe.c (revision dfdd013d)
1c35323b6SMatthew Dillon /*
2*dfdd013dSMatthew Dillon  * Copyright (c) 2003,2004,2020 The DragonFly Project.  All rights reserved.
38c10bfcfSMatthew Dillon  *
48c10bfcfSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
58c10bfcfSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6c35323b6SMatthew Dillon  *
7c35323b6SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8c35323b6SMatthew Dillon  * modification, are permitted provided that the following conditions
9c35323b6SMatthew Dillon  * are met:
108c10bfcfSMatthew Dillon  *
11c35323b6SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12c35323b6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13c35323b6SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
148c10bfcfSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
158c10bfcfSMatthew Dillon  *    the documentation and/or other materials provided with the
168c10bfcfSMatthew Dillon  *    distribution.
178c10bfcfSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
188c10bfcfSMatthew Dillon  *    contributors may be used to endorse or promote products derived
198c10bfcfSMatthew Dillon  *    from this software without specific, prior written permission.
20c35323b6SMatthew Dillon  *
218c10bfcfSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
228c10bfcfSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
238c10bfcfSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
248c10bfcfSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
258c10bfcfSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
268c10bfcfSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
278c10bfcfSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
288c10bfcfSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
298c10bfcfSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
308c10bfcfSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
318c10bfcfSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32c35323b6SMatthew Dillon  * SUCH DAMAGE.
33c35323b6SMatthew Dillon  */
34c35323b6SMatthew Dillon 
35c35323b6SMatthew Dillon #include <sys/param.h>
36c35323b6SMatthew Dillon #include <sys/systm.h>
37c35323b6SMatthew Dillon #include <sys/kernel.h>
38c35323b6SMatthew Dillon #include <sys/slaballoc.h>
3929a9f975Szrj #include <sys/malloc.h>
40c35323b6SMatthew Dillon #include <sys/mbuf.h>
41c35323b6SMatthew Dillon #include <sys/vmmeter.h>
42c35323b6SMatthew Dillon #include <sys/lock.h>
43c35323b6SMatthew Dillon #include <sys/thread.h>
44c35323b6SMatthew Dillon #include <sys/globaldata.h>
45853af6ebSJoerg Sonnenberger #include <sys/mpipe.h>
46e669f796SMatthew Dillon #include <sys/kthread.h>
47e669f796SMatthew Dillon 
48e669f796SMatthew Dillon struct mpipe_callback {
49e669f796SMatthew Dillon 	STAILQ_ENTRY(mpipe_callback) entry;
50e669f796SMatthew Dillon 	void (*func)(void *arg1, void *arg2);
51e669f796SMatthew Dillon 	void *arg1;
52e669f796SMatthew Dillon 	void *arg2;
53e669f796SMatthew Dillon };
54e669f796SMatthew Dillon 
55dff43ec9SSascha Wildner static MALLOC_DEFINE(M_MPIPEARY, "MPipe Array", "Auxiliary MPIPE structure");
56c35323b6SMatthew Dillon 
57e669f796SMatthew Dillon static void mpipe_thread(void *arg);
58e669f796SMatthew Dillon 
59c35323b6SMatthew Dillon /*
60c35323b6SMatthew Dillon  * Initialize a malloc pipeline for the specified malloc type and allocation
61537f47f3SMatthew Dillon  * size.  Create an array to cache up to nom_count buffers and preallocate
62537f47f3SMatthew Dillon  * them.
63c35323b6SMatthew Dillon  */
64c35323b6SMatthew Dillon void
mpipe_init(malloc_pipe_t mpipe,malloc_type_t type,int bytes,int nnom,int nmax,int mpflags,void (* construct)(void *,void *),void (* deconstruct)(void *,void *),void * priv)65c35323b6SMatthew Dillon mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes,
66537f47f3SMatthew Dillon 	int nnom, int nmax,
67fdec03d6SVenkatesh Srinivas 	int mpflags,
68fdec03d6SVenkatesh Srinivas 	void (*construct)(void *, void *),
69fdec03d6SVenkatesh Srinivas 	void (*deconstruct)(void *, void *),
70fdec03d6SVenkatesh Srinivas 	void *priv)
71c35323b6SMatthew Dillon {
72537f47f3SMatthew Dillon     int n;
73537f47f3SMatthew Dillon 
74537f47f3SMatthew Dillon     if (nnom < 1)
75537f47f3SMatthew Dillon 	nnom = 1;
76537f47f3SMatthew Dillon     if (nmax < 0)
77537f47f3SMatthew Dillon 	nmax = 0x7FFF0000;	/* some very large number */
78537f47f3SMatthew Dillon     if (nmax < nnom)
79537f47f3SMatthew Dillon 	nmax = nnom;
80c35323b6SMatthew Dillon     bzero(mpipe, sizeof(struct malloc_pipe));
81c35323b6SMatthew Dillon     mpipe->type = type;
82c35323b6SMatthew Dillon     mpipe->bytes = bytes;
83537f47f3SMatthew Dillon     mpipe->mpflags = mpflags;
84fdec03d6SVenkatesh Srinivas     mpipe->construct = construct;
85537f47f3SMatthew Dillon     mpipe->deconstruct = deconstruct;
86fdec03d6SVenkatesh Srinivas     mpipe->priv = priv;
87537f47f3SMatthew Dillon     if ((mpflags & MPF_NOZERO) == 0)
88537f47f3SMatthew Dillon 	mpipe->mflags |= M_ZERO;
89e976d337SMatthew Dillon     if (mpflags & MPF_INT)
90e976d337SMatthew Dillon 	mpipe->mflags |= M_USE_RESERVE | M_USE_INTERRUPT_RESERVE;
91537f47f3SMatthew Dillon     mpipe->ary_count = nnom;
925597811dSJoerg Sonnenberger     mpipe->max_count = nmax;
93efda3bd0SMatthew Dillon     mpipe->array = kmalloc(nnom * sizeof(mpipe->array[0]), M_MPIPEARY,
94537f47f3SMatthew Dillon 			    M_WAITOK | M_ZERO);
95c35323b6SMatthew Dillon 
96537f47f3SMatthew Dillon     while (mpipe->free_count < nnom) {
97537f47f3SMatthew Dillon 	n = mpipe->free_count;
98efda3bd0SMatthew Dillon 	mpipe->array[n] = kmalloc(bytes, mpipe->type, M_WAITOK | mpipe->mflags);
990a5a7d91SVenkatesh Srinivas 	if (construct)
100fdec03d6SVenkatesh Srinivas 	    construct(mpipe->array[n], priv);
101537f47f3SMatthew Dillon 	++mpipe->free_count;
102c35323b6SMatthew Dillon 	++mpipe->total_count;
103853af6ebSJoerg Sonnenberger     }
104e669f796SMatthew Dillon     STAILQ_INIT(&mpipe->queue);
105d12e3a62SVenkatesh Srinivas 
106a3c18566SMatthew Dillon     lwkt_token_init(&mpipe->token, "mpipe token");
107e669f796SMatthew Dillon 
108e669f796SMatthew Dillon     /*
109e669f796SMatthew Dillon      * Create a support thread for the mpipe queue
110e669f796SMatthew Dillon      */
111e669f796SMatthew Dillon     if (mpflags & MPF_CALLBACK) {
112e669f796SMatthew Dillon 	    kthread_create(mpipe_thread, mpipe, &mpipe->thread,
113e669f796SMatthew Dillon 			   "mpipe_%s", type->ks_shortdesc);
114e669f796SMatthew Dillon     }
115c35323b6SMatthew Dillon }
116c35323b6SMatthew Dillon 
1170d356308SMatthew Dillon /*
1180d356308SMatthew Dillon  * Destroy a previously initialized mpipe.  This routine can also safely be
1190d356308SMatthew Dillon  * called on an uninitialized mpipe structure if it was zero'd or mpipe_done()
1200d356308SMatthew Dillon  * was previously called on it.
1210d356308SMatthew Dillon  */
122c35323b6SMatthew Dillon void
mpipe_done(malloc_pipe_t mpipe)123c35323b6SMatthew Dillon mpipe_done(malloc_pipe_t mpipe)
124c35323b6SMatthew Dillon {
125537f47f3SMatthew Dillon     void *buf;
126537f47f3SMatthew Dillon     int n;
127c35323b6SMatthew Dillon 
128537f47f3SMatthew Dillon     KKASSERT(mpipe->free_count == mpipe->total_count);	/* no outstanding mem */
129e669f796SMatthew Dillon 
130e669f796SMatthew Dillon     /*
131e669f796SMatthew Dillon      * Clean up the kthread
132e669f796SMatthew Dillon      */
133e669f796SMatthew Dillon     lwkt_gettoken(&mpipe->token);
134e669f796SMatthew Dillon     mpipe->mpflags |= MPF_EXITING;
135e669f796SMatthew Dillon     while (mpipe->thread) {
136e669f796SMatthew Dillon 	wakeup(&mpipe->queue);
137e669f796SMatthew Dillon 	tsleep(mpipe, 0, "mpipex", 1);
138e669f796SMatthew Dillon     }
139e669f796SMatthew Dillon 
140e669f796SMatthew Dillon     /*
141e669f796SMatthew Dillon      * Clean up the mpipe buffers
142e669f796SMatthew Dillon      */
1430d356308SMatthew Dillon     for (n = mpipe->free_count - 1; n >= 0; --n) {
144537f47f3SMatthew Dillon 	buf = mpipe->array[n];
145537f47f3SMatthew Dillon 	mpipe->array[n] = NULL;
146c35323b6SMatthew Dillon 	KKASSERT(buf != NULL);
147537f47f3SMatthew Dillon 	if (mpipe->deconstruct)
148fdec03d6SVenkatesh Srinivas 	    mpipe->deconstruct(buf, mpipe->priv);
149efda3bd0SMatthew Dillon 	kfree(buf, mpipe->type);
150c35323b6SMatthew Dillon     }
1510d356308SMatthew Dillon     mpipe->free_count = 0;
1520d356308SMatthew Dillon     mpipe->total_count = 0;
1530d356308SMatthew Dillon     if (mpipe->array) {
154efda3bd0SMatthew Dillon 	kfree(mpipe->array, M_MPIPEARY);
1550d356308SMatthew Dillon 	mpipe->array = NULL;
1560d356308SMatthew Dillon     }
157e669f796SMatthew Dillon     lwkt_reltoken(&mpipe->token);
158d12e3a62SVenkatesh Srinivas     lwkt_token_uninit(&mpipe->token);
159c35323b6SMatthew Dillon }
160c35323b6SMatthew Dillon 
161c35323b6SMatthew Dillon /*
162e669f796SMatthew Dillon  * mpipe support thread for request failures when mpipe_alloc_callback()
163e669f796SMatthew Dillon  * is called.
164*dfdd013dSMatthew Dillon  *
165*dfdd013dSMatthew Dillon  * Only set MPF_QUEUEWAIT if entries are pending in the queue.  If no entries
166*dfdd013dSMatthew Dillon  * are pending and a new entry is added, other code will set MPF_QUEUEWAIT
167*dfdd013dSMatthew Dillon  * for us.
168e669f796SMatthew Dillon  */
169e669f796SMatthew Dillon static void
mpipe_thread(void * arg)170e669f796SMatthew Dillon mpipe_thread(void *arg)
171e669f796SMatthew Dillon {
172e669f796SMatthew Dillon     malloc_pipe_t mpipe = arg;
173e669f796SMatthew Dillon     struct mpipe_callback *mcb;
174e669f796SMatthew Dillon 
175e669f796SMatthew Dillon     lwkt_gettoken(&mpipe->token);
176e669f796SMatthew Dillon     while ((mpipe->mpflags & MPF_EXITING) == 0) {
177e669f796SMatthew Dillon 	while (mpipe->free_count &&
178e669f796SMatthew Dillon 	       (mcb = STAILQ_FIRST(&mpipe->queue)) != NULL) {
179e669f796SMatthew Dillon 		STAILQ_REMOVE(&mpipe->queue, mcb, mpipe_callback, entry);
180e669f796SMatthew Dillon 		mcb->func(mcb->arg1, mcb->arg2);
181e669f796SMatthew Dillon 		kfree(mcb, M_MPIPEARY);
182e669f796SMatthew Dillon 	}
183*dfdd013dSMatthew Dillon 	if (STAILQ_FIRST(&mpipe->queue))
184e669f796SMatthew Dillon 		mpipe->mpflags |= MPF_QUEUEWAIT;
185e669f796SMatthew Dillon 	tsleep(&mpipe->queue, 0, "wait", 0);
186e669f796SMatthew Dillon     }
187e669f796SMatthew Dillon     mpipe->thread = NULL;
188e669f796SMatthew Dillon     lwkt_reltoken(&mpipe->token);
189*dfdd013dSMatthew Dillon     wakeup(mpipe);
190e669f796SMatthew Dillon }
191e669f796SMatthew Dillon 
192e669f796SMatthew Dillon 
193e669f796SMatthew Dillon /*
194e669f796SMatthew Dillon  * Allocate an entry (inline suppot routine).  The allocation is guarenteed
195537f47f3SMatthew Dillon  * to return non-NULL up to the nominal count after which it may return NULL.
196537f47f3SMatthew Dillon  * Note that the implementation is defined to be allowed to block for short
197e669f796SMatthew Dillon  * periods of time.
198e669f796SMatthew Dillon  *
199e669f796SMatthew Dillon  * Use mpipe_alloc_callback() for non-blocking operation with a callback
200e669f796SMatthew Dillon  * Use mpipe_alloc_nowait() for non-blocking operation without a callback
201e669f796SMatthew Dillon  * Use mpipe_alloc_waitok() for blocking operation & guarenteed non-NULL
202c35323b6SMatthew Dillon  */
203e669f796SMatthew Dillon static __inline
204c35323b6SMatthew Dillon void *
_mpipe_alloc_locked(malloc_pipe_t mpipe,int mfailed)205e669f796SMatthew Dillon _mpipe_alloc_locked(malloc_pipe_t mpipe, int mfailed)
206c35323b6SMatthew Dillon {
207537f47f3SMatthew Dillon     void *buf;
208537f47f3SMatthew Dillon     int n;
209c35323b6SMatthew Dillon 
210537f47f3SMatthew Dillon     if ((n = mpipe->free_count) != 0) {
211537f47f3SMatthew Dillon 	/*
212537f47f3SMatthew Dillon 	 * Use a free entry if it exists.
213537f47f3SMatthew Dillon 	 */
214537f47f3SMatthew Dillon 	--n;
215537f47f3SMatthew Dillon 	buf = mpipe->array[n];
216537f47f3SMatthew Dillon 	mpipe->array[n] = NULL;	/* sanity check, not absolutely needed */
217537f47f3SMatthew Dillon 	mpipe->free_count = n;
218e669f796SMatthew Dillon     } else if (mpipe->total_count >= mpipe->max_count || mfailed) {
219537f47f3SMatthew Dillon 	/*
220537f47f3SMatthew Dillon 	 * Return NULL if we have hit our limit
221537f47f3SMatthew Dillon 	 */
222537f47f3SMatthew Dillon 	buf = NULL;
2235597811dSJoerg Sonnenberger     } else {
224537f47f3SMatthew Dillon 	/*
225537f47f3SMatthew Dillon 	 * Otherwise try to malloc() non-blocking.
226537f47f3SMatthew Dillon 	 */
227efda3bd0SMatthew Dillon 	buf = kmalloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
228fdec03d6SVenkatesh Srinivas 	if (buf) {
229537f47f3SMatthew Dillon 	    ++mpipe->total_count;
2300a5a7d91SVenkatesh Srinivas 	    if (mpipe->construct)
231fdec03d6SVenkatesh Srinivas 	        mpipe->construct(buf, mpipe->priv);
232fdec03d6SVenkatesh Srinivas 	}
233c35323b6SMatthew Dillon     }
234c35323b6SMatthew Dillon     return(buf);
235c35323b6SMatthew Dillon }
236c35323b6SMatthew Dillon 
237c35323b6SMatthew Dillon /*
238e669f796SMatthew Dillon  * Nominal non-blocking mpipe allocation
239e669f796SMatthew Dillon  */
240e669f796SMatthew Dillon void *
mpipe_alloc_nowait(malloc_pipe_t mpipe)241e669f796SMatthew Dillon mpipe_alloc_nowait(malloc_pipe_t mpipe)
242e669f796SMatthew Dillon {
243e669f796SMatthew Dillon     void *buf;
244e669f796SMatthew Dillon 
245e669f796SMatthew Dillon     lwkt_gettoken(&mpipe->token);
246e669f796SMatthew Dillon     buf = _mpipe_alloc_locked(mpipe, 0);
247e669f796SMatthew Dillon     lwkt_reltoken(&mpipe->token);
248e669f796SMatthew Dillon 
249e669f796SMatthew Dillon     return(buf);
250e669f796SMatthew Dillon }
251e669f796SMatthew Dillon 
252e669f796SMatthew Dillon /*
253e669f796SMatthew Dillon  * non-blocking mpipe allocation with callback for retry.
254e669f796SMatthew Dillon  *
255e669f796SMatthew Dillon  * If NULL is returned func(arg) is queued and will be called back when
256e669f796SMatthew Dillon  * space is likely (but not necessarily) available.
257e669f796SMatthew Dillon  *
258e669f796SMatthew Dillon  * If non-NULL is returned func(arg) is ignored.
259e669f796SMatthew Dillon  */
260e669f796SMatthew Dillon void *
mpipe_alloc_callback(malloc_pipe_t mpipe,void (* func)(void * arg1,void * arg2),void * arg1,void * arg2)261e669f796SMatthew Dillon mpipe_alloc_callback(malloc_pipe_t mpipe, void (*func)(void *arg1, void *arg2),
262e669f796SMatthew Dillon 		     void *arg1, void *arg2)
263e669f796SMatthew Dillon {
264e669f796SMatthew Dillon     struct mpipe_callback *mcb;
265e669f796SMatthew Dillon     void *buf;
266e669f796SMatthew Dillon 
267e669f796SMatthew Dillon     lwkt_gettoken(&mpipe->token);
268e669f796SMatthew Dillon     buf = _mpipe_alloc_locked(mpipe, 0);
269e669f796SMatthew Dillon     if (buf == NULL) {
270e669f796SMatthew Dillon 	mcb = kmalloc(sizeof(*mcb), M_MPIPEARY, M_INTWAIT);
271e669f796SMatthew Dillon 	buf = _mpipe_alloc_locked(mpipe, 0);
272e669f796SMatthew Dillon 	if (buf == NULL) {
273e669f796SMatthew Dillon 	    mcb->func = func;
274e669f796SMatthew Dillon 	    mcb->arg1 = arg1;
275e669f796SMatthew Dillon 	    mcb->arg2 = arg2;
276e669f796SMatthew Dillon 	    STAILQ_INSERT_TAIL(&mpipe->queue, mcb, entry);
277*dfdd013dSMatthew Dillon 	    mpipe->mpflags |= MPF_QUEUEWAIT;	/* for mpipe_thread() */
278e669f796SMatthew Dillon 	} else {
279e669f796SMatthew Dillon 	    kfree(mcb, M_MPIPEARY);
280e669f796SMatthew Dillon 	}
281e669f796SMatthew Dillon     }
282e669f796SMatthew Dillon     lwkt_reltoken(&mpipe->token);
283e669f796SMatthew Dillon 
284e669f796SMatthew Dillon     return(buf);
285e669f796SMatthew Dillon }
286e669f796SMatthew Dillon 
287e669f796SMatthew Dillon /*
288e669f796SMatthew Dillon  * This function can be called to nominally wait until resources are
289e669f796SMatthew Dillon  * available and mpipe_alloc_nowait() is likely to return non-NULL.
290e669f796SMatthew Dillon  *
291e669f796SMatthew Dillon  * NOTE: mpipe_alloc_nowait() can still return NULL.
292e669f796SMatthew Dillon  */
293e669f796SMatthew Dillon void
mpipe_wait(malloc_pipe_t mpipe)294e669f796SMatthew Dillon mpipe_wait(malloc_pipe_t mpipe)
295e669f796SMatthew Dillon {
296e669f796SMatthew Dillon     if (mpipe->free_count == 0) {
297e669f796SMatthew Dillon 	lwkt_gettoken(&mpipe->token);
298e669f796SMatthew Dillon 	while ((mpipe->mpflags & MPF_EXITING) == 0) {
299e669f796SMatthew Dillon 	    if (mpipe->free_count)
300e669f796SMatthew Dillon 		    break;
301e669f796SMatthew Dillon 	    mpipe->mpflags |= MPF_QUEUEWAIT;
302e669f796SMatthew Dillon 	    tsleep(&mpipe->queue, 0, "wait", 0);
303e669f796SMatthew Dillon 	}
304e669f796SMatthew Dillon 	lwkt_reltoken(&mpipe->token);
305e669f796SMatthew Dillon     }
306e669f796SMatthew Dillon }
307e669f796SMatthew Dillon 
308e669f796SMatthew Dillon /*
309537f47f3SMatthew Dillon  * Allocate an entry, block until the allocation succeeds.  This may cause
310537f47f3SMatthew Dillon  * us to block waiting for a prior allocation to be freed.
311537f47f3SMatthew Dillon  */
312537f47f3SMatthew Dillon void *
mpipe_alloc_waitok(malloc_pipe_t mpipe)313537f47f3SMatthew Dillon mpipe_alloc_waitok(malloc_pipe_t mpipe)
314537f47f3SMatthew Dillon {
315537f47f3SMatthew Dillon     void *buf;
316537f47f3SMatthew Dillon     int mfailed;
317537f47f3SMatthew Dillon 
318d12e3a62SVenkatesh Srinivas     lwkt_gettoken(&mpipe->token);
319537f47f3SMatthew Dillon     mfailed = 0;
320e669f796SMatthew Dillon     while ((buf = _mpipe_alloc_locked(mpipe, mfailed)) == NULL) {
321537f47f3SMatthew Dillon 	/*
322537f47f3SMatthew Dillon 	 * Block if we have hit our limit
323537f47f3SMatthew Dillon 	 */
324537f47f3SMatthew Dillon 	mpipe->pending = 1;
325537f47f3SMatthew Dillon 	tsleep(mpipe, 0, "mpipe1", 0);
326537f47f3SMatthew Dillon 	mfailed = 1;
327537f47f3SMatthew Dillon     }
328d12e3a62SVenkatesh Srinivas     lwkt_reltoken(&mpipe->token);
329e669f796SMatthew Dillon 
330537f47f3SMatthew Dillon     return(buf);
331537f47f3SMatthew Dillon }
332537f47f3SMatthew Dillon 
333537f47f3SMatthew Dillon /*
334537f47f3SMatthew Dillon  * Free an entry, unblock any waiters.  Allow NULL.
335c35323b6SMatthew Dillon  */
336c35323b6SMatthew Dillon void
mpipe_free(malloc_pipe_t mpipe,void * buf)337537f47f3SMatthew Dillon mpipe_free(malloc_pipe_t mpipe, void *buf)
338c35323b6SMatthew Dillon {
339537f47f3SMatthew Dillon     int n;
340c35323b6SMatthew Dillon 
341537f47f3SMatthew Dillon     if (buf == NULL)
342537f47f3SMatthew Dillon 	return;
343537f47f3SMatthew Dillon 
344d12e3a62SVenkatesh Srinivas     lwkt_gettoken(&mpipe->token);
345537f47f3SMatthew Dillon     if ((n = mpipe->free_count) < mpipe->ary_count) {
346537f47f3SMatthew Dillon 	/*
347537f47f3SMatthew Dillon 	 * Free slot available in free array (LIFO)
348537f47f3SMatthew Dillon 	 */
349537f47f3SMatthew Dillon 	mpipe->array[n] = buf;
3505597811dSJoerg Sonnenberger 	++mpipe->free_count;
351537f47f3SMatthew Dillon 	if ((mpipe->mpflags & (MPF_CACHEDATA|MPF_NOZERO)) == 0)
352537f47f3SMatthew Dillon 	    bzero(buf, mpipe->bytes);
353e669f796SMatthew Dillon 	if (mpipe->mpflags & MPF_QUEUEWAIT) {
354e669f796SMatthew Dillon 		mpipe->mpflags &= ~MPF_QUEUEWAIT;
355d12e3a62SVenkatesh Srinivas 		lwkt_reltoken(&mpipe->token);
356e669f796SMatthew Dillon 		wakeup(&mpipe->queue);
357e669f796SMatthew Dillon 	} else {
358e669f796SMatthew Dillon 		lwkt_reltoken(&mpipe->token);
359e669f796SMatthew Dillon 	}
360537f47f3SMatthew Dillon 	/*
361537f47f3SMatthew Dillon 	 * Wakeup anyone blocked in mpipe_alloc_*().
362537f47f3SMatthew Dillon 	 */
3635597811dSJoerg Sonnenberger 	if (mpipe->pending) {
3645597811dSJoerg Sonnenberger 	    mpipe->pending = 0;
3655597811dSJoerg Sonnenberger 	    wakeup(mpipe);
3665597811dSJoerg Sonnenberger 	}
367537f47f3SMatthew Dillon     } else {
368537f47f3SMatthew Dillon 	/*
369537f47f3SMatthew Dillon 	 * All the free slots are full, free the buffer directly.
370537f47f3SMatthew Dillon 	 */
371537f47f3SMatthew Dillon 	--mpipe->total_count;
372537f47f3SMatthew Dillon 	KKASSERT(mpipe->total_count >= mpipe->free_count);
373537f47f3SMatthew Dillon 	if (mpipe->deconstruct)
374fdec03d6SVenkatesh Srinivas 	    mpipe->deconstruct(buf, mpipe->priv);
375d12e3a62SVenkatesh Srinivas 	lwkt_reltoken(&mpipe->token);
376efda3bd0SMatthew Dillon 	kfree(buf, mpipe->type);
3775597811dSJoerg Sonnenberger     }
3785597811dSJoerg Sonnenberger }
3795597811dSJoerg Sonnenberger 
380