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