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