clone.c revision 170289
1/*-
2 * Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/sound/clone.c 170289 2007-06-04 18:25:08Z dwmalone $
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/conf.h>
32#include <sys/kernel.h>
33#include <sys/lock.h>
34#include <sys/malloc.h>
35#include <sys/mutex.h>
36#include <sys/proc.h>
37
38#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
39#include <dev/sound/pcm/sound.h>
40#endif
41
42#include <dev/sound/clone.h>
43
44/*
45 * So here we go again, another clonedevs manager. Unlike default clonedevs,
46 * this clone manager is designed to withstand various abusive behavior
47 * (such as 'while : ; do ls /dev/whatever ; done', etc.), reusable object
48 * after reaching certain expiration threshold, aggressive garbage collector,
49 * transparent device allocator and concurrency handling across multiple
50 * thread/proc. Due to limited information given by dev_clone EVENTHANDLER,
51 * we don't have much clues whether the caller wants a real open() or simply
52 * making fun of us with things like stat(), mtime() etc. Assuming that:
53 * 1) Time window between dev_clone EH <-> real open() should be small
54 * enough and 2) mtime()/stat() etc. always looks like a half way / stalled
55 * operation, we can decide whether a new cdev must be created, old
56 * (expired) cdev can be reused or an existing cdev can be shared.
57 *
58 * Most of the operations and logics are generic enough and can be applied
59 * on other places (such as if_tap, snp, etc).  Perhaps this can be
60 * rearranged to complement clone_*(). However, due to this still being
61 * specific to the sound driver (and as a proof of concept on how it can be
62 * done), si_drv2 is used to keep the pointer of the clone list entry to
63 * avoid expensive lookup.
64 */
65
66/* clone entry */
67struct snd_clone_entry {
68	TAILQ_ENTRY(snd_clone_entry) link;
69	struct snd_clone *parent;
70	struct cdev *devt;
71	struct timespec tsp;
72	uint32_t flags;
73	pid_t pid;
74	int unit;
75};
76
77/* clone manager */
78struct snd_clone {
79	TAILQ_HEAD(link_head, snd_clone_entry) head;
80#ifdef SND_DIAGNOSTIC
81	struct mtx *lock;
82#endif
83	struct timespec tsp;
84	int refcount;
85	int size;
86	int typemask;
87	int maxunit;
88	int deadline;
89	uint32_t flags;
90};
91
92#ifdef SND_DIAGNOSTIC
93#define SND_CLONE_LOCKASSERT(x)		do {			\
94	if ((x)->lock == NULL)					\
95		panic("%s(): NULL mutex!", __func__);		\
96	if (mtx_owned((x)->lock) == 0)				\
97		panic("%s(): mutex not owned!", __func__);	\
98} while(0)
99#define SND_CLONE_ASSERT(x, y)		do {			\
100	if (!(x))						\
101		panic y;					\
102} while(0)
103#else
104#define SND_CLONE_LOCKASSERT(...)
105#define SND_CLONE_ASSERT(x...)		KASSERT(x)
106#endif
107
108/*
109 * Shamelessly ripped off from vfs_subr.c
110 * We need at least 1/HZ precision as default timestamping.
111 */
112enum { SND_TSP_SEC, SND_TSP_HZ, SND_TSP_USEC, SND_TSP_NSEC };
113
114static int snd_timestamp_precision = SND_TSP_HZ;
115TUNABLE_INT("hw.snd.timestamp_precision", &snd_timestamp_precision);
116
117void
118snd_timestamp(struct timespec *tsp)
119{
120	struct timeval tv;
121
122	switch (snd_timestamp_precision) {
123	case SND_TSP_SEC:
124		tsp->tv_sec = time_second;
125		tsp->tv_nsec = 0;
126		break;
127	case SND_TSP_HZ:
128		getnanouptime(tsp);
129		break;
130	case SND_TSP_USEC:
131		microuptime(&tv);
132		TIMEVAL_TO_TIMESPEC(&tv, tsp);
133		break;
134	case SND_TSP_NSEC:
135		nanouptime(tsp);
136		break;
137	default:
138		snd_timestamp_precision = SND_TSP_HZ;
139		getnanouptime(tsp);
140		break;
141	}
142}
143
144#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
145static int
146sysctl_hw_snd_timestamp_precision(SYSCTL_HANDLER_ARGS)
147{
148	int err, val;
149
150	val = snd_timestamp_precision;
151	err = sysctl_handle_int(oidp, &val, 0, req);
152	if (err == 0 && req->newptr != NULL) {
153		switch (val) {
154		case SND_TSP_SEC:
155		case SND_TSP_HZ:
156		case SND_TSP_USEC:
157		case SND_TSP_NSEC:
158			snd_timestamp_precision = val;
159			break;
160		default:
161			break;
162		}
163	}
164
165	return (err);
166}
167SYSCTL_PROC(_hw_snd, OID_AUTO, timestamp_precision, CTLTYPE_INT | CTLFLAG_RW,
168    0, sizeof(int), sysctl_hw_snd_timestamp_precision, "I",
169    "timestamp precision (0=s 1=hz 2=us 3=ns)");
170#endif
171
172/*
173 * snd_clone_create() : Return opaque allocated clone manager. Mutex is
174 * not a mandatory requirement if the caller can guarantee safety across
175 * concurrent access.
176 */
177struct snd_clone *
178snd_clone_create(
179#ifdef SND_DIAGNOSTIC
180    struct mtx *lock,
181#endif
182    int typemask, int maxunit, int deadline, uint32_t flags)
183{
184	struct snd_clone *c;
185
186	SND_CLONE_ASSERT(!(typemask & ~SND_CLONE_MAXUNIT),
187	    ("invalid typemask: 0x%08x", typemask));
188	SND_CLONE_ASSERT(maxunit == -1 ||
189	    !(maxunit & ~(~typemask & SND_CLONE_MAXUNIT)),
190	    ("maxunit overflow: typemask=0x%08x maxunit=%d",
191	    typemask, maxunit));
192	SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
193	    ("invalid clone flags=0x%08x", flags));
194
195	c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK | M_ZERO);
196#ifdef SND_DIAGNOSTIC
197	c->lock = lock;
198#endif
199	c->refcount = 0;
200	c->size = 0;
201	c->typemask = typemask;
202	c->maxunit = (maxunit == -1) ? (~typemask & SND_CLONE_MAXUNIT) :
203	    maxunit;
204	c->deadline = deadline;
205	c->flags = flags;
206	snd_timestamp(&c->tsp);
207	TAILQ_INIT(&c->head);
208
209	return (c);
210}
211
212int
213snd_clone_busy(struct snd_clone *c)
214{
215	struct snd_clone_entry *ce;
216
217	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
218	SND_CLONE_LOCKASSERT(c);
219
220	if (c->size == 0)
221		return (0);
222
223	TAILQ_FOREACH(ce, &c->head, link) {
224		if ((ce->flags & SND_CLONE_BUSY) ||
225		    (ce->devt != NULL && ce->devt->si_threadcount != 0))
226			return (EBUSY);
227	}
228
229	return (0);
230}
231
232/*
233 * snd_clone_enable()/disable() : Suspend/resume clone allocation through
234 * snd_clone_alloc(). Everything else will not be affected by this.
235 */
236int
237snd_clone_enable(struct snd_clone *c)
238{
239	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
240	SND_CLONE_LOCKASSERT(c);
241
242	if (c->flags & SND_CLONE_ENABLE)
243		return (EINVAL);
244
245	c->flags |= SND_CLONE_ENABLE;
246
247	return (0);
248}
249
250int
251snd_clone_disable(struct snd_clone *c)
252{
253	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
254	SND_CLONE_LOCKASSERT(c);
255
256	if (!(c->flags & SND_CLONE_ENABLE))
257		return (EINVAL);
258
259	c->flags &= ~SND_CLONE_ENABLE;
260
261	return (0);
262}
263
264/*
265 * Getters / Setters. Not worth explaining :)
266 */
267int
268snd_clone_getsize(struct snd_clone *c)
269{
270	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
271	SND_CLONE_LOCKASSERT(c);
272
273	return (c->size);
274}
275
276int
277snd_clone_getmaxunit(struct snd_clone *c)
278{
279	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
280	SND_CLONE_LOCKASSERT(c);
281
282	return (c->maxunit);
283}
284
285int
286snd_clone_setmaxunit(struct snd_clone *c, int maxunit)
287{
288	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
289	SND_CLONE_LOCKASSERT(c);
290	SND_CLONE_ASSERT(maxunit == -1 ||
291	    !(maxunit & ~(~c->typemask & SND_CLONE_MAXUNIT)),
292	    ("maxunit overflow: typemask=0x%08x maxunit=%d",
293	    c->typemask, maxunit));
294
295	c->maxunit = (maxunit == -1) ? (~c->typemask & SND_CLONE_MAXUNIT) :
296	    maxunit;
297
298	return (c->maxunit);
299}
300
301int
302snd_clone_getdeadline(struct snd_clone *c)
303{
304	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
305	SND_CLONE_LOCKASSERT(c);
306
307	return (c->deadline);
308}
309
310int
311snd_clone_setdeadline(struct snd_clone *c, int deadline)
312{
313	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
314	SND_CLONE_LOCKASSERT(c);
315
316	c->deadline = deadline;
317
318	return (c->deadline);
319}
320
321int
322snd_clone_gettime(struct snd_clone *c, struct timespec *tsp)
323{
324	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
325	SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
326	SND_CLONE_LOCKASSERT(c);
327
328	*tsp = c->tsp;
329
330	return (0);
331}
332
333uint32_t
334snd_clone_getflags(struct snd_clone *c)
335{
336	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
337	SND_CLONE_LOCKASSERT(c);
338
339	return (c->flags);
340}
341
342uint32_t
343snd_clone_setflags(struct snd_clone *c, uint32_t flags)
344{
345	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
346	SND_CLONE_LOCKASSERT(c);
347	SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
348	    ("invalid clone flags=0x%08x", flags));
349
350	c->flags = flags;
351
352	return (c->flags);
353}
354
355int
356snd_clone_getdevtime(struct cdev *dev, struct timespec *tsp)
357{
358	struct snd_clone_entry *ce;
359
360	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
361	SND_CLONE_ASSERT(tsp != NULL, ("NULL timespec"));
362
363	ce = dev->si_drv2;
364	if (ce == NULL)
365		return (ENODEV);
366
367	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
368	SND_CLONE_LOCKASSERT(ce->parent);
369
370	*tsp = ce->tsp;
371
372	return (0);
373}
374
375uint32_t
376snd_clone_getdevflags(struct cdev *dev)
377{
378	struct snd_clone_entry *ce;
379
380	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
381
382	ce = dev->si_drv2;
383	if (ce == NULL)
384		return (0xffffffff);
385
386	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
387	SND_CLONE_LOCKASSERT(ce->parent);
388
389	return (ce->flags);
390}
391
392uint32_t
393snd_clone_setdevflags(struct cdev *dev, uint32_t flags)
394{
395	struct snd_clone_entry *ce;
396
397	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
398	SND_CLONE_ASSERT(!(flags & ~SND_CLONE_DEVMASK),
399	    ("invalid clone dev flags=0x%08x", flags));
400
401	ce = dev->si_drv2;
402	if (ce == NULL)
403		return (0xffffffff);
404
405	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
406	SND_CLONE_LOCKASSERT(ce->parent);
407
408	ce->flags = flags;
409
410	return (ce->flags);
411}
412
413/* Elapsed time conversion to ms */
414#define SND_CLONE_ELAPSED(x, y)						\
415	((((x)->tv_sec - (y)->tv_sec) * 1000) +				\
416	(((y)->tv_nsec > (x)->tv_nsec) ?				\
417	(((1000000000L + (x)->tv_nsec -					\
418	(y)->tv_nsec) / 1000000) - 1000) :				\
419	(((x)->tv_nsec - (y)->tv_nsec) / 1000000)))
420
421#define SND_CLONE_EXPIRED(x, y, z)					\
422	((x)->deadline < 1 ||						\
423	((y)->tv_sec - (z)->tv_sec) > ((x)->deadline / 1000) ||		\
424	SND_CLONE_ELAPSED(y, z) > (x)->deadline)
425
426/*
427 * snd_clone_gc() : Garbage collector for stalled, expired objects. Refer to
428 * clone.h for explanations on GC settings.
429 */
430int
431snd_clone_gc(struct snd_clone *c)
432{
433	struct snd_clone_entry *ce, *tce;
434	struct timespec now;
435	int pruned;
436
437	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
438	SND_CLONE_LOCKASSERT(c);
439
440	if (!(c->flags & SND_CLONE_GC_ENABLE) || c->size == 0)
441		return (0);
442
443	snd_timestamp(&now);
444
445	/*
446	 * Bail out if the last clone handler was invoked below the deadline
447	 * threshold.
448	 */
449	if ((c->flags & SND_CLONE_GC_EXPIRED) &&
450	    !SND_CLONE_EXPIRED(c, &now, &c->tsp))
451		return (0);
452
453	pruned = 0;
454
455	/*
456	 * Visit each object in reverse order. If the object is still being
457	 * referenced by a valid open(), skip it. Look for expired objects
458	 * and either revoke its clone invocation status or mercilessly
459	 * throw it away.
460	 */
461	TAILQ_FOREACH_REVERSE_SAFE(ce, &c->head, link_head, link, tce) {
462		if (!(ce->flags & SND_CLONE_BUSY) &&
463		    (!(ce->flags & SND_CLONE_INVOKE) ||
464		    SND_CLONE_EXPIRED(c, &now, &ce->tsp))) {
465			if ((c->flags & SND_CLONE_GC_REVOKE) ||
466			    ce->devt->si_threadcount != 0) {
467				ce->flags &= ~SND_CLONE_INVOKE;
468				ce->pid = -1;
469			} else {
470				TAILQ_REMOVE(&c->head, ce, link);
471				destroy_dev(ce->devt);
472				free(ce, M_DEVBUF);
473				c->size--;
474			}
475			pruned++;
476		}
477	}
478
479	/* return total pruned objects */
480	return (pruned);
481}
482
483void
484snd_clone_destroy(struct snd_clone *c)
485{
486	struct snd_clone_entry *ce;
487
488	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
489	SND_CLONE_ASSERT(c->refcount == 0, ("refcount > 0"));
490	SND_CLONE_LOCKASSERT(c);
491
492	while (!TAILQ_EMPTY(&c->head)) {
493		ce = TAILQ_FIRST(&c->head);
494		TAILQ_REMOVE(&c->head, ce, link);
495		if (ce->devt != NULL)
496			destroy_dev(ce->devt);
497		free(ce, M_DEVBUF);
498	}
499
500	free(c, M_DEVBUF);
501}
502
503/*
504 * snd_clone_acquire() : The vital part of concurrency management. Must be
505 * called somewhere at the beginning of open() handler. ENODEV is not really
506 * fatal since it just tell the caller that this is not cloned stuff.
507 * EBUSY is *real*, don't forget that!
508 */
509int
510snd_clone_acquire(struct cdev *dev)
511{
512	struct snd_clone_entry *ce;
513
514	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
515
516	ce = dev->si_drv2;
517	if (ce == NULL)
518		return (ENODEV);
519
520	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
521	SND_CLONE_LOCKASSERT(ce->parent);
522
523	ce->flags &= ~SND_CLONE_INVOKE;
524
525	if (ce->flags & SND_CLONE_BUSY)
526		return (EBUSY);
527
528	ce->flags |= SND_CLONE_BUSY;
529
530	return (0);
531}
532
533/*
534 * snd_clone_release() : Release busy status. Must be called somewhere at
535 * the end of close() handler, or somewhere after fail open().
536 */
537int
538snd_clone_release(struct cdev *dev)
539{
540	struct snd_clone_entry *ce;
541
542	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
543
544	ce = dev->si_drv2;
545	if (ce == NULL)
546		return (ENODEV);
547
548	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
549	SND_CLONE_LOCKASSERT(ce->parent);
550
551	ce->flags &= ~SND_CLONE_INVOKE;
552
553	if (!(ce->flags & SND_CLONE_BUSY))
554		return (EBADF);
555
556	ce->flags &= ~SND_CLONE_BUSY;
557	ce->pid = -1;
558
559	return (0);
560}
561
562/*
563 * snd_clone_ref/unref() : Garbage collector reference counter. To make
564 * garbage collector run automatically, the sequence must be something like
565 * this (both in open() and close() handlers):
566 *
567 *  open() - 1) snd_clone_acquire()
568 *           2) .... check check ... if failed, snd_clone_release()
569 *           3) Success. Call snd_clone_ref()
570 *
571 * close() - 1) .... check check check ....
572 *           2) Success. snd_clone_release()
573 *           3) snd_clone_unref() . Garbage collector will run at this point
574 *              if this is the last referenced object.
575 */
576int
577snd_clone_ref(struct cdev *dev)
578{
579	struct snd_clone_entry *ce;
580	struct snd_clone *c;
581
582	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
583
584	ce = dev->si_drv2;
585	if (ce == NULL)
586		return (0);
587
588	c = ce->parent;
589	SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
590	SND_CLONE_ASSERT(c->refcount >= 0, ("refcount < 0"));
591	SND_CLONE_LOCKASSERT(c);
592
593	return (++c->refcount);
594}
595
596int
597snd_clone_unref(struct cdev *dev)
598{
599	struct snd_clone_entry *ce;
600	struct snd_clone *c;
601
602	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
603
604	ce = dev->si_drv2;
605	if (ce == NULL)
606		return (0);
607
608	c = ce->parent;
609	SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
610	SND_CLONE_ASSERT(c->refcount > 0, ("refcount <= 0"));
611	SND_CLONE_LOCKASSERT(c);
612
613	c->refcount--;
614
615	/*
616	 * Run automatic garbage collector, if needed.
617	 */
618	if ((c->flags & SND_CLONE_GC_UNREF) &&
619	    (!(c->flags & SND_CLONE_GC_LASTREF) ||
620	    (c->refcount == 0 && (c->flags & SND_CLONE_GC_LASTREF))))
621		(void)snd_clone_gc(c);
622
623	return (c->refcount);
624}
625
626void
627snd_clone_register(struct snd_clone_entry *ce, struct cdev *dev)
628{
629	SND_CLONE_ASSERT(ce != NULL, ("NULL snd_clone_entry"));
630	SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
631	SND_CLONE_ASSERT(dev->si_drv2 == NULL, ("dev->si_drv2 not NULL"));
632	SND_CLONE_ASSERT((ce->flags & SND_CLONE_ALLOC) == SND_CLONE_ALLOC,
633	    ("invalid clone alloc flags=0x%08x", ce->flags));
634	SND_CLONE_ASSERT(ce->devt == NULL, ("ce->devt not NULL"));
635	SND_CLONE_ASSERT(ce->unit == dev2unit(dev),
636	    ("invalid unit ce->unit=0x%08x dev2unit=0x%08x",
637	    ce->unit, dev2unit(dev)));
638
639	SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
640	SND_CLONE_LOCKASSERT(ce->parent);
641
642	dev->si_drv2 = ce;
643	ce->devt = dev;
644	ce->flags &= ~SND_CLONE_ALLOC;
645	ce->flags |= SND_CLONE_INVOKE;
646}
647
648struct snd_clone_entry *
649snd_clone_alloc(struct snd_clone *c, struct cdev **dev, int *unit, int tmask)
650{
651	struct snd_clone_entry *ce, *after, *bce, *cce, *nce, *tce;
652	struct timespec now;
653	int cunit, allocunit;
654	pid_t curpid;
655
656	SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
657	SND_CLONE_LOCKASSERT(c);
658	SND_CLONE_ASSERT(dev != NULL, ("NULL dev pointer"));
659	SND_CLONE_ASSERT((c->typemask & tmask) == tmask,
660	    ("invalid tmask: typemask=0x%08x tmask=0x%08x",
661	    c->typemask, tmask));
662	SND_CLONE_ASSERT(unit != NULL, ("NULL unit pointer"));
663	SND_CLONE_ASSERT(*unit == -1 || !(*unit & (c->typemask | tmask)),
664	    ("typemask collision: typemask=0x%08x tmask=0x%08x *unit=%d",
665	    c->typemask, tmask, *unit));
666
667	if (!(c->flags & SND_CLONE_ENABLE) ||
668	    (*unit != -1 && *unit > c->maxunit))
669		return (NULL);
670
671	ce = NULL;
672	after = NULL;
673	bce = NULL;	/* "b"usy candidate */
674	cce = NULL;	/* "c"urthread/proc candidate */
675	nce = NULL;	/* "n"ull, totally unbusy candidate */
676	tce = NULL;	/* Last "t"ry candidate */
677	cunit = 0;
678	allocunit = (*unit == -1) ? 0 : *unit;
679	curpid = curthread->td_proc->p_pid;
680
681	snd_timestamp(&now);
682
683	TAILQ_FOREACH(ce, &c->head, link) {
684		/*
685		 * Sort incrementally according to device type.
686		 */
687		if (tmask > (ce->unit & c->typemask)) {
688			if (cunit == 0)
689				after = ce;
690			continue;
691		} else if (tmask < (ce->unit & c->typemask))
692			break;
693
694		/*
695		 * Shoot.. this is where the grumpiness begin. Just
696		 * return immediately.
697		 */
698		if (*unit != -1 && *unit == (ce->unit & ~tmask))
699			goto snd_clone_alloc_out;
700
701		cunit++;
702		/*
703		 * Simmilar device type. Sort incrementally according
704		 * to allocation unit. While here, look for free slot
705		 * and possible collision for new / future allocation.
706		 */
707		if (*unit == -1 && (ce->unit & ~tmask) == allocunit)
708			allocunit++;
709		if ((ce->unit & ~tmask) < allocunit)
710			after = ce;
711		/*
712		 * Clone logic:
713		 *   1. Look for non busy, but keep track of the best
714		 *      possible busy cdev.
715		 *   2. Look for the best (oldest referenced) entry that is
716		 *      in a same process / thread.
717		 *   3. Look for the best (oldest referenced), absolute free
718		 *      entry.
719		 *   4. Lastly, look for the best (oldest referenced)
720		 *      any entries that doesn't fit with anything above.
721		 */
722		if (ce->flags & SND_CLONE_BUSY) {
723			if (ce->devt != NULL && (bce == NULL ||
724			    timespeccmp(&ce->tsp, &bce->tsp, <)))
725				bce = ce;
726			continue;
727		}
728		if (ce->pid == curpid &&
729		    (cce == NULL || timespeccmp(&ce->tsp, &cce->tsp, <)))
730			cce = ce;
731		else if (!(ce->flags & SND_CLONE_INVOKE) &&
732		    (nce == NULL || timespeccmp(&ce->tsp, &nce->tsp, <)))
733			nce = ce;
734		else if (tce == NULL || timespeccmp(&ce->tsp, &tce->tsp, <))
735			tce = ce;
736	}
737	if (*unit != -1)
738		goto snd_clone_alloc_new;
739	else if (cce != NULL) {
740		/* Same proc entry found, go for it */
741		ce = cce;
742		goto snd_clone_alloc_out;
743	} else if (nce != NULL) {
744		/*
745		 * Next, try absolute free entry. If the calculated
746		 * allocunit is smaller, create new entry instead.
747		 */
748		if (allocunit < (nce->unit & ~tmask))
749			goto snd_clone_alloc_new;
750		ce = nce;
751		goto snd_clone_alloc_out;
752	} else if (allocunit > c->maxunit) {
753		/*
754		 * Maximum allowable unit reached. Try returning any
755		 * available cdev and hope for the best. If the lookup is
756		 * done for things like stat(), mtime() etc. , things should
757		 * be ok. Otherwise, open() handler should do further checks
758		 * and decide whether to return correct error code or not.
759		 */
760		if (tce != NULL) {
761			ce = tce;
762			goto snd_clone_alloc_out;
763		} else if (bce != NULL) {
764			ce = bce;
765			goto snd_clone_alloc_out;
766		}
767		return (NULL);
768	}
769
770snd_clone_alloc_new:
771	/*
772	 * No free entries found, and we still haven't reached maximum
773	 * allowable units. Allocate, setup a minimal unique entry with busy
774	 * status so nobody will monkey on this new entry since we had to
775	 * give up locking for further setup. Unit magic is set right here
776	 * to avoid collision with other contesting handler.
777	 */
778	ce = malloc(sizeof(*ce), M_DEVBUF, M_NOWAIT | M_ZERO);
779	if (ce == NULL) {
780		if (*unit != -1)
781			return (NULL);
782		/*
783		 * We're being dense, ignorance is bliss,
784		 * Super Regulatory Measure (TM).. TRY AGAIN!
785		 */
786		if (nce != NULL) {
787			ce = nce;
788			goto snd_clone_alloc_out;
789		} else if (tce != NULL) {
790			ce = tce;
791			goto snd_clone_alloc_out;
792		} else if (bce != NULL) {
793			ce = bce;
794			goto snd_clone_alloc_out;
795		}
796		return (NULL);
797	}
798	/* Setup new entry */
799	ce->parent = c;
800	ce->unit = tmask | allocunit;
801	ce->pid = curpid;
802	ce->tsp = now;
803	ce->flags |= SND_CLONE_ALLOC;
804	if (after != NULL) {
805		TAILQ_INSERT_AFTER(&c->head, after, ce, link);
806	} else {
807		TAILQ_INSERT_HEAD(&c->head, ce, link);
808	}
809	c->size++;
810	c->tsp = now;
811	/*
812	 * Save new allocation unit for caller which will be used
813	 * by make_dev().
814	 */
815	*unit = allocunit;
816
817	return (ce);
818
819snd_clone_alloc_out:
820	/*
821	 * Set, mark, timestamp the entry if this is a truly free entry.
822	 * Leave busy entry alone.
823	 */
824	if (!(ce->flags & SND_CLONE_BUSY)) {
825		ce->pid = curpid;
826		ce->tsp = now;
827		ce->flags |= SND_CLONE_INVOKE;
828	}
829	c->tsp = now;
830	*dev = ce->devt;
831
832	return (NULL);
833}
834