|
|
1.1 ! root 1: #define _DDI_DKI 1 ! 2: #define _DDI_DKI_IMPL 1 ! 3: #define _SYSV4 1 ! 4: ! 5: /* ! 6: */ ! 7: ! 8: #include <common/ccompat.h> ! 9: #include <kernel/fhsys.h> ! 10: #include <kernel/strmlib.h> ! 11: #include <sys/confinfo.h> ! 12: #include <sys/types.h> ! 13: #include <sys/kmem.h> ! 14: #include <sys/poll.h> ! 15: #include <sys/ksynch.h> ! 16: #include <sys/file.h> ! 17: #include <sys/uio.h> ! 18: #include <sys/cmn_err.h> ! 19: #include <sys/errno.h> ! 20: #include <sys/signal.h> ! 21: #include <stropts.h> ! 22: #include <string.h> ! 23: #include <poll.h> ! 24: ! 25: /* ! 26: * The following function (local to this module) is forward-referenced due to ! 27: * the mutual recursion between the final close process and the streams unlink ! 28: * code. ! 29: */ ! 30: ! 31: __LOCAL__ int SHEAD_DO_CLOSE __PROTO ((shead_t * sheadp, int mode, ! 32: cred_t * credp)); ! 33: ! 34: ! 35: lkinfo_t __stream_schedule_lkinfo = { ! 36: "STREAMS queue schedule", INTERNAL_LOCK ! 37: }; ! 38: ! 39: lkinfo_t __stream_event_lkinfo = { ! 40: "STREAMS bufcall ()/esbbcall () event list", INTERNAL_LOCK ! 41: }; ! 42: ! 43: __LOCAL__ lkinfo_t _stream_head_lkinfo = { ! 44: "stream head lock", INTERNAL_LOCK ! 45: }; ! 46: ! 47: ! 48: /* ! 49: * Allocate and initialize a queue pair. This function only performs a partial ! 50: * initialization; many other fields are filled in by the caller, usually from ! 51: * fields supplied in the "streamtab" structure. ! 52: * ! 53: * Since at initial stream open time we we be allocating at least two queue ! 54: * pairs and one or two stream head structures, we try to satisfy all those ! 55: * allocations in one step here. ! 56: * ! 57: * The "npairs" argument indicates the number of queue pairs to be allocated. ! 58: * The "extra" argument is the number of additional bytes to allocate over and ! 59: * above the memory for the queue pairs. ! 60: * ! 61: * Call only from base level. This function may sleep. ! 62: */ ! 63: ! 64: #if __USE_PROTO__ ! 65: __LOCAL__ queue_t * (QUEUE_ALLOC) (int npairs, size_t extra) ! 66: #else ! 67: __LOCAL__ queue_t * ! 68: QUEUE_ALLOC __ARGS ((npairs, extra)) ! 69: int npairs; ! 70: size_t extra; ! 71: #endif ! 72: { ! 73: queue_t * q; ! 74: queue_t * init; ! 75: int count; ! 76: ! 77: ASSERT (npairs > 0 && npairs < 3); ! 78: ! 79: /* ! 80: * We use kmem_zalloc () to allocate this space so we can sleaze our ! 81: * way out of most of the initialization work. ! 82: */ ! 83: ! 84: if ((q = (queue_t *) kmem_zalloc (2 * npairs * sizeof (* q) + extra, ! 85: KM_SLEEP)) == NULL) ! 86: return NULL; ! 87: ! 88: init = q; ! 89: count = npairs; ! 90: ! 91: do { ! 92: /* ! 93: * First, initialise the read side of the queue. While we are ! 94: * at it, we link the "q_next" members of multiple queues for ! 95: * a read side; if we treat the value "q" that we are going to ! 96: * return to the caller as the stream head, the links run from ! 97: * the last entry we initialize towards the first one. ! 98: */ ! 99: ! 100: if (count > 1) ! 101: (init + 2)->q_next = init; ! 102: ! 103: init->q_flag = QWANTR | QREADR | QPROCSOFF; ! 104: ! 105: SFREEZE_INIT (init); ! 106: ! 107: init ++; ! 108: ! 109: ! 110: /* ! 111: * Next, work on the write side. For multiple queues, the ! 112: * write size "q_next" links run from the "head" to the device. ! 113: */ ! 114: ! 115: if (count > 1) ! 116: init->q_next = init + 2; ! 117: ! 118: init->q_flag = QWANTR | QPROCSOFF; ! 119: ! 120: SFREEZE_INIT (init); ! 121: ! 122: init ++; ! 123: } while (-- count > 0); ! 124: ! 125: ! 126: /* ! 127: * We put a pointer to any "extra" space that the caller requested in ! 128: * the "q_ptr" fields of the first two queues allocated, since they ! 129: * will almost always be the stream head queue pair. ! 130: */ ! 131: ! 132: if (extra > 0) { ! 133: ! 134: q->q_ptr = (char *) q + 2 * sizeof (* q) * npairs; ! 135: W (q)->q_ptr = q->q_ptr; ! 136: } ! 137: ! 138: return q; ! 139: } ! 140: ! 141: ! 142: /* ! 143: * Set a queue's initial watermark data and some other stuff. ! 144: */ ! 145: ! 146: #if __USE_PROTO__ ! 147: __LOCAL__ void (QUEUE_INITOPT) (queue_t * q) ! 148: #else ! 149: __LOCAL__ void ! 150: QUEUE_INITOPT __ARGS ((q)) ! 151: queue_t * q; ! 152: #endif ! 153: { ! 154: struct module_info ! 155: * mi = q->q_qinfo->qi_minfo; ! 156: ! 157: q->q_minpsz = mi->mi_minpsz; ! 158: q->q_maxpsz = mi->mi_maxpsz; ! 159: q->q_hiwat = mi->mi_hiwat; ! 160: q->q_lowat = mi->mi_lowat; ! 161: } ! 162: ! 163: ! 164: /* ! 165: * Set up a queue pair's initial options. ! 166: */ ! 167: ! 168: typedef enum { ! 169: QI_NORMAL, ! 170: QI_MUX ! 171: } qiflag_t; ! 172: ! 173: #if __USE_PROTO__ ! 174: __LOCAL__ void (QUEUE_INIT) (queue_t * q, struct streamtab * stab, ! 175: qiflag_t mux) ! 176: #else ! 177: void ! 178: QUEUE_INIT __ARGS ((q, stab, mux)) ! 179: queue_t * q; ! 180: struct streamtab ! 181: * stab; ! 182: qiflag_t mux; ! 183: #endif ! 184: { ! 185: q->q_qinfo = mux == QI_NORMAL ? stab->st_rdinit : stab->st_muxrinit; ! 186: QUEUE_INITOPT (q); ! 187: ! 188: q = W (q); ! 189: ! 190: q->q_qinfo = mux == QI_NORMAL ? stab->st_wrinit : stab->st_muxwinit; ! 191: QUEUE_INITOPT (q); ! 192: } ! 193: ! 194: ! 195: /* ! 196: * This function is the dual to the QBAND_ALLOC () function, freeing any ! 197: * allocated "qband" structures associated with the given queue. ! 198: * ! 199: * The caller must have the queue frozen or not linked on any stream. ! 200: */ ! 201: ! 202: #if __USE_PROTO__ ! 203: void (QBAND_FREE) (queue_t * q) ! 204: #else ! 205: void ! 206: QBAND_FREE __ARGS ((q)) ! 207: queue_t * q; ! 208: #endif ! 209: { ! 210: qband_t * scan; ! 211: qband_t * prev; ! 212: int nbands; ! 213: ! 214: QUEUE_TRACE (q, "QBAND_FREE"); ! 215: ! 216: /* ! 217: * We use flags in the "qband" entries to locate allocation ! 218: * boundaries rather than trying to recover this information purely ! 219: * from comparing addresses (although since the address comparisons ! 220: * provide an extra check we do that too). In theory, an allocator ! 221: * might not need extra information stored in the arena yet might ! 222: * fail if adjacent allocations are coalesced into a single free (). ! 223: * ! 224: * I don't know of any allocators with this property, but one might ! 225: * exist. ! 226: * ! 227: * This code will work just fine under the allocation scheme which ! 228: * keeps the QBAND entries in a single vector, so we don't need to ! 229: * conditionalize this code at all. ! 230: */ ! 231: ! 232: nbands = 0; ! 233: ! 234: for (prev = scan = q->q_bandp ; scan != NULL ; scan = scan->qb_next) { ! 235: ! 236: if ((scan->qb_flag & QB_FIRST) != 0) { ! 237: ! 238: ASSERT (nbands > 0); ! 239: ! 240: kmem_free (prev, sizeof (* prev) * nbands); ! 241: ! 242: nbands = 1; ! 243: prev = scan; ! 244: } else { ! 245: ! 246: ASSERT (scan == prev + nbands); ! 247: nbands ++; ! 248: } ! 249: } ! 250: ! 251: if (nbands > 0) ! 252: kmem_free (prev, sizeof (* prev) * nbands); ! 253: } ! 254: ! 255: ! 256: /* ! 257: * Destroy an individual queue. ! 258: */ ! 259: ! 260: #if __USE_PROTO__ ! 261: __LOCAL__ void (QUEUE_DESTROY) (queue_t * q) ! 262: #else ! 263: __LOCAL__ void ! 264: QUEUE_DESTROY __ARGS ((q)) ! 265: queue_t * q; ! 266: #endif ! 267: { ! 268: mblk_t * mp; ! 269: mblk_t * next; ! 270: ! 271: QSCHED_UNSCHEDULE (q, str_mem->sm_sched); ! 272: ! 273: /* ! 274: * Free all the memory allocated to messages that remain on the queue. ! 275: */ ! 276: ! 277: for (mp = q->q_first ; mp != NULL ; mp = next) { ! 278: ! 279: next = mp->b_next; ! 280: freemsg (mp); ! 281: } ! 282: ! 283: if ((q->q_flag & QWANTW) != 0) ! 284: QUEUE_BACKENAB (q); ! 285: ! 286: SFREEZE_DESTROY (q); ! 287: ! 288: if (q->q_nband > 0) ! 289: QBAND_FREE (q); ! 290: } ! 291: ! 292: ! 293: /* ! 294: * Destroy and release the memory for a queue pair or group of pairs. The ! 295: * arguments passed to this function should match those used to allocate a ! 296: * pair or group of pairs exactly. This can easily be done by recognising the ! 297: * various canonical forms for stream structures; modules are always lone ! 298: * queue pairs, regular streams match a driver and stream head (with ! 299: * associated extra data for the stream head), and stream pipes consist of ! 300: * two pairs of queue structures with two head structures. ! 301: */ ! 302: ! 303: #if __USE_PROTO__ ! 304: __LOCAL__ void (QUEUE_FREE) (queue_t * rq, int npairs, size_t extra) ! 305: #else ! 306: __LOCAL__ void ! 307: QUEUE_FREE __ARGS ((rq, npairs, extra)) ! 308: queue_t * rq; ! 309: int npairs; ! 310: size_t extra; ! 311: #endif ! 312: { ! 313: queue_t * destroy; ! 314: int count; ! 315: ! 316: ASSERT (rq != NULL); ! 317: ASSERT (npairs > 0 && npairs < 3); ! 318: ! 319: destroy = rq; ! 320: count = npairs * 2; ! 321: ! 322: do { ! 323: ! 324: QUEUE_DESTROY (destroy); ! 325: destroy ++; ! 326: } while (-- count > 0); ! 327: ! 328: kmem_free (rq, 2 * sizeof (* rq) * npairs + extra); ! 329: } ! 330: ! 331: ! 332: /* ! 333: * STREAM HEAD MANAGEMENT NOTES: ! 334: * ! 335: * The management of stream head structures introduces some interesting ! 336: * synchronization problems arising from the interaction of the rules ! 337: * associated with driver close routines and the fact that stream head ! 338: * structures are dynamically allocated. ! 339: * ! 340: * The first problem is really one of specification; what does it mean for a ! 341: * driver close () entry point to return EINTR? System V does not talk about ! 342: * this case specifically, so we prohibit it by treating error returns from ! 343: * the close () entry point uniformly by still actually closing the device. ! 344: * ! 345: * The second problem is this; a driver should not be re-opened until the ! 346: * close process has completed. However, completion of the close process will ! 347: * normally involve deallocation of the stream head (where presumably the ! 348: * open routines are waiting). ! 349: * ! 350: * Our problem is that it is not possible to reliably determine whether there ! 351: * are any other contexts waiting on a sleep lock. While it might be possible ! 352: * to do so using SLEEP_LOCKAVAIL (), this would require that the calling ! 353: * context release the lock. Under a plausible implementation of SLEEP_LOCK () ! 354: * where sleep locks are basically implemented with the sleep () and wakeup () ! 355: * functions and a "locked" flag, there will be no way for a process to find ! 356: * out whether there are any functions waiting on the lock, since the unlock ! 357: * implementation could simply clear the "locked" flag and issue wakeup (), ! 358: * so that there could be any number of contexts waiting to run and test the ! 359: * "locked" flag, yet SLEEP_LOCKAVAIL () in the calling context would return ! 360: * true. Deallocating the lock at this time would be potentially disastrous. ! 361: * ! 362: * Actually, even a quality implementation of sleep locks (such as is provided ! 363: * with this STREAMS system) cannot be easily used this way, since it is very ! 364: * difficult to ensure that the information returned by SLEEP_LOCKAVAIL () is ! 365: * current. ! 366: * ! 367: * The situation can be resolved by maintaining a count of processes wishing ! 368: * to lock the item. The count can be maintained by using the basic-lock ! 369: * action associated with DDI/DKI synchronization variables, and the new ! 370: * SV_SIGNAL () operation can be used to pass the ownership of the lock to ! 371: * a waiting process reliably. ! 372: * ! 373: * Once this is in place, it becomes clear how the count of waiting processes ! 374: * can be used to simplify the destruction of stream heads; essentially, ! 375: * when a process wishes to release the "lock" on the stream head, if both ! 376: * the open count and the waiting count are 0, then the memory for the item ! 377: * can be safely released. Otherwise, control simply passes to the next ! 378: * waiting process. ! 379: * ! 380: * So, if a process is performing a final close on a stream, and some open ! 381: * requests are queued, the close will leave the stream's memory alone and ! 382: * simply pass it on to the waiting open (which can detect that the stream ! 383: * needs to be treated as new since the open count is 0). If the waiting open ! 384: * was interrupted by a signal, it would still have to decrement the count of ! 385: * waiting processes before it releases its lock, at which time it would know ! 386: * to remove the item from the directory and release the memory. ! 387: * ! 388: * For this to work properly takes some coordination in the policy for the ! 389: * directory; the basic lock used to guard lock operations should be held ! 390: * during searches of the directory to ensure that the count value is correct ! 391: * with respect to all processes; a process that has a pointer to the stream ! 392: * head (obtained from the directory) which it has not incremented the count ! 393: * for is an error. Note that this only applies to operations which might ! 394: * later affect the count, of course. ! 395: * ! 396: * ! 397: * STREAM OPERATIONS AND LOCKS: ! 398: * ! 399: * open () This operation cannot begin while there is a final close in ! 400: * progress. If this operation increments the "open count" before ! 401: * calling the device open routines, it is possible that it will ! 402: * also have to perform final close duties if a driver or module ! 403: * fails the open. This function may cause the creation of a new ! 404: * queue pair and directory entry. ! 405: * ! 406: * The multiprocessor DDI/DKI also mandates that a particular ! 407: * device number's open () routine only have one instance active ! 408: * at any given time. ! 409: * ! 410: * close () Normally, this does not require extended locking, but the case ! 411: * of beginning a final close is special, since only then will ! 412: * the queue drain and final close procedures begin. Since there ! 413: * cannot be outstanding ioctl ()s during final close, the timer ! 414: * code used to control ioctl ()s can be shared with this for ! 415: * timing out while waiting for a write queue to drain. ! 416: * ! 417: * read (), getmsg (), getpmsg () ! 418: * Under normal circumstances, these functions require no special ! 419: * treatment. It would be desirable to support an extension to ! 420: * STREAMS which supported "safe" multiple readers, where the ! 421: * serialization of reads is guaranteed. ! 422: * ! 423: * write (), putmsg (), putpmsg () ! 424: * These functions require little special treatment. It would be ! 425: * desirable to support an extension to STREAMS which guaranteed ! 426: * serialization of writes, for instance to guarantee unlimited- ! 427: * length atomic pipe writes. ! 428: * ! 429: * ioctl () Depending on the details of the operation, we may need ! 430: * ! 431: * a read lock on the stream head (eg. I_GETCLTIME). ! 432: * a write lock on the stream head (eg. I_SRDOPT). ! 433: * a block on open and pop (I_PUSH). ! 434: * a block on close and push (I_POP). ! 435: * a long-term lock on the message queue. ! 436: * ! 437: * The long-term lock operations revolve around the operations ! 438: * that send messages downstream : I_LINK, I_UNLINK, I_PLINK, ! 439: * I_PUNLINK, and I_STR. These operations are also special in ! 440: * that they are capable of timing out. ! 441: * ! 442: * Since the close or open routines invoked by an I_PUSH or I_POP ! 443: * operation may block, they require analagous locking to the ! 444: * open () and close () cases. ! 445: * ! 446: * LOCK SUMMARY: ! 447: * EXCLUSIVE LONG-TERM LOCK WITH OPTIONAL TIMEOUT: ! 448: * open/close category: ! 449: * open (), close (), I_PUSH, I_POP ! 450: * ioctl category: ! 451: * I_LINK, I_UNLINK, I_PLINK, I_PUNLINK, I_STR ! 452: * ! 453: * In theory, a single lock will do. However, once we take into ! 454: * account terminal behaviour w.r.t. CLOCAL and other similar ! 455: * situations, it seems that creating the subcategories above will ! 456: * suit us better. ! 457: * ! 458: * Final close is a special case that blocks all other cases, which ! 459: * can be distinguished fairly clearly. ! 460: * ! 461: * STREAM HEAD WRITE LOCK: ! 462: * I_SRDOPT, I_SETSIG, I_SWROPT, I_SETCLTIME ! 463: * Certain stream head message processing routines may also write ! 464: * lock the stream head, such as M_SETOPT processing. ! 465: * ! 466: * All other streams operations should acquire a stream head read lock ! 467: * before reading stream head variables. ! 468: */ ! 469: /* ! 470: * STREAM HEAD WAIT NOTES: ! 471: * ! 472: * In addition to the above discussion about locking, there are other ! 473: * operations that may cause a process to block while at the stream head. For ! 474: * instance, read (), write (), I_RECVFD, and I_STR operations may cause the ! 475: * outer context to block until some kind of message arrives. ! 476: * ! 477: * The question we are immediately faced with is what level of specificity to ! 478: * provide in the arrangement of synchronization variables and basic locks. ! 479: * Until the implementation is complete and we can perform detailed ! 480: * measurements with a variety of (pathological) loads on a variety of ! 481: * systems, we really don't know. For simplicity, the current system performs ! 482: * all stream head blocking by sleeping on the "sh_wait_sv" synchronization ! 483: * variable that is also used by the above locking operations. ! 484: * ! 485: * However, to give some isolation from changes in this scheme, we mandate a ! 486: * generic layer to deal with this. Not only does this insulate operations ! 487: * from the details of synchronization, but it allows us to perform some ! 488: * simple optimizations that may allow this simple scheme to perform better. ! 489: */ ! 490: ! 491: ! 492: /* ! 493: * Initialize a stream head structure, assuming that memory was allocated with ! 494: * kmem_zalloc () and so NULL pointers and 0-value fields need not be filled ! 495: * in. ! 496: * ! 497: * This function may sleep waiting for memory to become available to allocate ! 498: * the locks needed by the stream head. ! 499: */ ! 500: ! 501: #if __USE_PROTO__ ! 502: __LOCAL__ void (SHEAD_INIT) (shead_t * sheadp, struct streamtab * stabp, ! 503: n_dev_t dev, queue_t * rq) ! 504: #else ! 505: __LOCAL__ void ! 506: SHEAD_INIT __ARGS ((sheadp, stabp, dev, rq)) ! 507: shead_t * sheadp; ! 508: struct streamtab ! 509: * stabp; ! 510: n_dev_t dev; ! 511: queue_t * rq; ! 512: #endif ! 513: { ! 514: ASSERT (sheadp != NULL); ! 515: ASSERT (rq != NULL); ! 516: ! 517: /* ! 518: * The sh_lock_count and sh_time_count members are initialized in the ! 519: * lock code. ! 520: */ ! 521: ! 522: ASSERT (sheadp->sh_open_count == 0); ! 523: ASSERT (sheadp->sh_attach_count == 0); ! 524: ASSERT (sheadp->sh_lock_count == 0); ! 525: ASSERT (sheadp->sh_time_count == 0); ! 526: ASSERT (sheadp->sh_rerrcode == 0); ! 527: ASSERT (sheadp->sh_werrcode == 0); ! 528: ASSERT (sheadp->sh_wroff == 0); ! 529: ! 530: ASSERT (sheadp->sh_read_bufcall == 0); ! 531: ASSERT (sheadp->sh_timeout_id == 0); ! 532: ! 533: ASSERT (sheadp->sh_sigs == NULL); ! 534: ASSERT (sheadp->sh_linked == NULL); ! 535: ASSERT (sheadp->sh_ioc_msg == NULL); ! 536: ! 537: ASSERT (rq->q_ptr == sheadp); ! 538: ! 539: sheadp->sh_dev = dev; ! 540: sheadp->sh_tab = stabp; ! 541: sheadp->sh_head = rq; ! 542: ! 543: sheadp->sh_pollhead = phalloc (KM_SLEEP); ! 544: sheadp->sh_flags = SH_MASTER; ! 545: sheadp->sh_readopt = RNORM | RPROTNORM; ! 546: ! 547: sheadp->sh_basic_lockp = LOCK_ALLOC (stream_head_hierarchy, plstr, ! 548: & _stream_head_lkinfo, KM_SLEEP); ! 549: sheadp->sh_wait_sv = SV_ALLOC (KM_SLEEP); ! 550: ! 551: ASSERT (sheadp->sh_basic_lockp != NULL || sheadp->sh_wait_sv != NULL); ! 552: ! 553: ! 554: /* ! 555: * The default time to wait for a queue to drain while closing is 15s. ! 556: */ ! 557: ! 558: sheadp->sh_cltime = drv_usectohz (15000000L); ! 559: } ! 560: ! 561: ! 562: /* ! 563: * Turn a stream head structure back into raw bits. ! 564: */ ! 565: ! 566: #if __USE_PROTO__ ! 567: __LOCAL__ void (SHEAD_DESTROY) (shead_t * sheadp) ! 568: #else ! 569: __LOCAL__ void ! 570: SHEAD_DESTROY __ARGS((sheadp)) ! 571: shead_t * sheadp; ! 572: #endif ! 573: { ! 574: ASSERT (sheadp != NULL); ! 575: ASSERT (sheadp->sh_sigs == NULL); ! 576: ASSERT (sheadp->sh_linked == NULL); ! 577: ! 578: ASSERT (sheadp->sh_open_count == 0); ! 579: ASSERT (sheadp->sh_attach_count == 0); ! 580: ASSERT (sheadp->sh_lock_count == 0); ! 581: ! 582: ASSERT (sheadp->sh_timeout_id == 0); ! 583: ! 584: if (sheadp->sh_read_bufcall != 0) ! 585: unbufcall (sheadp->sh_read_bufcall); ! 586: ! 587: LOCK_DEALLOC (sheadp->sh_basic_lockp); ! 588: SV_DEALLOC (sheadp->sh_wait_sv); ! 589: ! 590: phfree (sheadp->sh_pollhead); ! 591: } ! 592: ! 593: ! 594: /* ! 595: * This function attempts to determine the appropriate id queue for a stream ! 596: * head based on cues in the stream head. ! 597: */ ! 598: ! 599: #if __USE_PROTO__ ! 600: __LOCAL__ slist_id_t (SHEAD_ID) (shead_t * sheadp) ! 601: #else ! 602: __LOCAL__ slist_id_t ! 603: SHEAD_ID __ARGS ((sheadp)) ! 604: shead_t * sheadp; ! 605: #endif ! 606: { ! 607: ASSERT (sheadp != NULL); ! 608: ! 609: if (SHEAD_IS_PIPE (sheadp)) ! 610: return PIPE_SLIST; ! 611: ! 612: return DEV_SLIST; ! 613: } ! 614: ! 615: ! 616: /* ! 617: * This function finds a stream head by looking up its device number, but ! 618: * nothing else. To call this function, the caller must have good reason to ! 619: * suspect that an open reference to the stream exists and isn't going to go ! 620: * away. ! 621: * ! 622: * If this routine returns NULL, then that is a serious error (which may be ! 623: * diagnosed by console messages), because it indicates that the caller has ! 624: * not got the claimed knowledge of the state of the system! ! 625: */ ! 626: ! 627: #if __USE_PROTO__ ! 628: shead_t * (SHEAD_FIND) (n_dev_t dev, slist_id_t id) ! 629: #else ! 630: shead_t * ! 631: SHEAD_FIND __ARGS ((dev, id)) ! 632: n_dev_t dev; ! 633: slist_id_t id; ! 634: #endif ! 635: { ! 636: shead_t * scan; ! 637: pl_t prev_pl; ! 638: ! 639: prev_pl = RW_RDLOCK (str_mem->sm_head_lock, plstr); ! 640: ! 641: for (scan = str_mem->sm_streams [id] ; scan != NULL ; ! 642: scan = scan->sh_next) { ! 643: ! 644: if (scan->sh_dev == dev) ! 645: break; ! 646: } ! 647: ! 648: RW_UNLOCK (str_mem->sm_head_lock, prev_pl); ! 649: ! 650: if (scan == NULL) ! 651: cmn_err (CE_WARN, "Unable to locate stream in SHEAD_FIND ()"); ! 652: else ! 653: ASSERT (SHEAD_ID (scan) == id); ! 654: ! 655: return scan; ! 656: } ! 657: ! 658: ! 659: /* ! 660: * This function attempts to locate an existing entry and increment its lock ! 661: * count atomically. ! 662: */ ! 663: ! 664: #if __USE_PROTO__ ! 665: __LOCAL__ shead_t * (SHEAD_FIND_AND_LOCK) (n_dev_t dev, slist_id_t id) ! 666: #else ! 667: __LOCAL__ shead_t * ! 668: SHEAD_FIND_AND_LOCK __ARGS ((dev, id)) ! 669: n_dev_t dev; ! 670: slist_id_t id; ! 671: #endif ! 672: { ! 673: shead_t * scan; ! 674: pl_t prev_pl; ! 675: ! 676: prev_pl = RW_RDLOCK (str_mem->sm_head_lock, plstr); ! 677: ! 678: for (scan = str_mem->sm_streams [id] ; scan != NULL ; ! 679: scan = scan->sh_next) { ! 680: ! 681: if (scan->sh_dev == dev) { ! 682: /* ! 683: * Now we have found the entry we want, increment the ! 684: * reference count atomically. We know that it will ! 685: * not disappear because of the read lock we have on ! 686: * the containing list. ! 687: */ ! 688: ! 689: (void) SHEAD_LOCK (scan); ! 690: ! 691: scan->sh_lock_count ++; ! 692: break; ! 693: } ! 694: } ! 695: ! 696: RW_UNLOCK (str_mem->sm_head_lock, prev_pl); ! 697: return scan; ! 698: } ! 699: ! 700: ! 701: /* ! 702: * This function adds a stream head to the global list. If an entry with the ! 703: * same ID is present on the list, this operation fails. ! 704: * ! 705: * The stream head should be locked against further opens at this point. ! 706: * ! 707: * The return value is 0 on success, -1 on error. ! 708: */ ! 709: ! 710: #if __USE_PROTO__ ! 711: __LOCAL__ int (SHEAD_ADD) (shead_t * sheadp) ! 712: #else ! 713: __LOCAL__ int ! 714: SHEAD_ADD __ARGS ((sheadp)) ! 715: shead_t * sheadp; ! 716: #endif ! 717: { ! 718: pl_t prev_pl; ! 719: shead_t * scan; ! 720: slist_id_t id; ! 721: ! 722: id = SHEAD_ID (sheadp); ! 723: ! 724: ASSERT (sheadp->sh_ref_count == 1); ! 725: ASSERT ((sheadp->sh_lock_mask & SH_OPENCLOSE) != 0); ! 726: ! 727: prev_pl = RW_WRLOCK (str_mem->sm_head_lock, plstr); ! 728: ! 729: for (scan = str_mem->sm_streams [id] ; scan != NULL ; ! 730: scan = scan->sh_next) { ! 731: ! 732: if (scan->sh_dev == sheadp->sh_dev) { ! 733: /* ! 734: * We have found a conflict. Unlock the list and ! 735: * return an error. ! 736: */ ! 737: ! 738: RW_UNLOCK (str_mem->sm_head_lock, prev_pl); ! 739: return -1; ! 740: } ! 741: } ! 742: ! 743: sheadp->sh_next = str_mem->sm_streams [id]; ! 744: str_mem->sm_streams [id] = sheadp; ! 745: ! 746: RW_UNLOCK (str_mem->sm_head_lock, prev_pl); ! 747: return 0; ! 748: } ! 749: ! 750: ! 751: /* ! 752: * This function changes the device number of a stream head for a clone open ! 753: * situation. The "st_dev" field of the stream head has to be changed with ! 754: * the stream head list lock held for writing to avoid confusing anyone who ! 755: * is looking for the original device number. ! 756: * ! 757: * Furthermore, the rename can fail because the new number is already in use. ! 758: * The return value is -1 on error, or 0 on success. ! 759: */ ! 760: ! 761: #if __USE_PROTO__ ! 762: __LOCAL__ int (SHEAD_RENAME) (shead_t * sheadp, n_dev_t dev) ! 763: #else ! 764: __LOCAL__ int ! 765: SHEAD_RENAME __ARGS ((sheadp, dev)) ! 766: shead_t * sheadp; ! 767: n_dev_t dev; ! 768: #endif ! 769: { ! 770: pl_t prev_pl; ! 771: shead_t * scan; ! 772: int ok = 0; /* flag whether stream is on list */ ! 773: slist_id_t id; ! 774: ! 775: id = SHEAD_ID (sheadp); ! 776: ! 777: prev_pl = RW_WRLOCK (str_mem->sm_head_lock, plstr); ! 778: ! 779: for (scan = str_mem->sm_streams [id] ; scan != NULL ; ! 780: scan = scan->sh_next) { ! 781: ! 782: if (scan->sh_dev == dev) { ! 783: /* ! 784: * We have found a conflict. Unlock the list and ! 785: * return an error. ! 786: */ ! 787: ! 788: RW_UNLOCK (str_mem->sm_head_lock, prev_pl); ! 789: return -1; ! 790: } ! 791: ! 792: if (scan == sheadp) ! 793: ok ++; /* Ok, we saw the item */ ! 794: } ! 795: ! 796: /* ! 797: * All OK, now change the name of the original stream head. ! 798: */ ! 799: ! 800: sheadp->sh_dev = dev; ! 801: RW_UNLOCK (str_mem->sm_head_lock, prev_pl); ! 802: ! 803: if (! ok) ! 804: cmn_err (CE_WARN, "SHEAD_RENAME () of unlisted stream head"); ! 805: ! 806: return 0; ! 807: } ! 808: ! 809: ! 810: /* ! 811: * This function decrements the link count of the stream head; this may cause ! 812: * the stream head to become unreferened, which means that the memory will be ! 813: * reclaimed. ! 814: */ ! 815: ! 816: #if __USE_PROTO__ ! 817: __LOCAL__ void (SHEAD_UNREFERENCE) (shead_t * sheadp) ! 818: #else ! 819: __LOCAL__ void ! 820: SHEAD_UNREFERENCE __ARGS ((sheadp)) ! 821: shead_t * sheadp; ! 822: #endif ! 823: { ! 824: slist_id_t id; ! 825: int unlink; ! 826: ! 827: SHEAD_ASSERT_LOCKED (sheadp); ! 828: ASSERT (sheadp == SHEAD_MASTER (sheadp)); ! 829: ASSERT (sheadp->sh_lock_count > 0); ! 830: ! 831: id = SHEAD_ID (sheadp); ! 832: ! 833: /* ! 834: * We will delete a stream if there are no references holding it open, ! 835: * either pending locks or open references. If this is a stream pipe, ! 836: * then we need to check boths ends of the stream pipe. Because this ! 837: * function is called from the sleep-locking code, we know that ! 838: * "sheadp" points to the master end. ! 839: */ ! 840: ! 841: unlink = sheadp->sh_open_count == 0 || ! 842: (SHEAD_IS_PIPE (sheadp) && ! 843: SHEAD_M2SLAVE (sheadp->sh_open_count) == 0); ! 844: ! 845: /* ! 846: * We normally assume that we won't be unlinking the stream, because ! 847: * to do that we need a lock on a global list (which is more expensive ! 848: * that a list on an individual stream). ! 849: * ! 850: * However, due to the relative hierarchy positions of the locks, if ! 851: * we discover we are likely to be the ones to dequeue the item, we ! 852: * take out a write lock then. ! 853: */ ! 854: ! 855: if (sheadp->sh_lock_count > 1 && ! unlink) { ! 856: /* ! 857: * Take the short path out. ! 858: */ ! 859: ! 860: sheadp->sh_lock_count --; ! 861: SHEAD_UNLOCK (sheadp, plbase); ! 862: return; ! 863: } ! 864: ! 865: /* ! 866: * Escalate to a write lock on the stream head; we will need ! 867: * to recheck to unlink condition after we escalate. ! 868: */ ! 869: ! 870: SHEAD_UNLOCK (sheadp, plbase); ! 871: ! 872: (void) RW_WRLOCK (str_mem->sm_head_lock, plstr); ! 873: (void) SHEAD_LOCK (sheadp); ! 874: ! 875: unlink = -- sheadp->sh_lock_count == 0 && ! 876: (sheadp->sh_open_count == 0 || ! 877: (SHEAD_IS_PIPE (sheadp) && ! 878: SHEAD_M2SLAVE (sheadp)->sh_open_count == 0)); ! 879: ! 880: SHEAD_UNLOCK (sheadp, plstr); ! 881: ! 882: if (unlink) { ! 883: shead_t * scan; ! 884: ! 885: /* ! 886: * Remove from the singly-threaded list by searching for the ! 887: * immediate predecessor entry in the list (if any). ! 888: */ ! 889: ! 890: if ((scan = str_mem->sm_streams [id]) == sheadp) ! 891: str_mem->sm_streams [id] = sheadp->sh_next; ! 892: else ! 893: do { ! 894: if (scan->sh_next == sheadp) { ! 895: ! 896: scan->sh_next = sheadp->sh_next; ! 897: break; ! 898: } ! 899: } while ((scan = scan->sh_next) != NULL); ! 900: ! 901: if (scan == NULL) ! 902: cmn_err (CE_WARN, "Failure unlinking stream from global directory"); ! 903: ! 904: /* ! 905: * Note that stream pipes consist of four queues and ! 906: * two stream heads! ! 907: */ ! 908: ! 909: SHEAD_DESTROY (sheadp); ! 910: ! 911: if (SHEAD_IS_PIPE (sheadp)) ! 912: QUEUE_FREE (sheadp->sh_head, 4, ! 913: 2 * sizeof (* sheadp)); ! 914: else ! 915: QUEUE_FREE (sheadp->sh_head, 2, sizeof (* sheadp)); ! 916: } ! 917: ! 918: RW_UNLOCK (str_mem->sm_head_lock, plbase); ! 919: } ! 920: ! 921: ! 922: /* ! 923: * This function attempts to locate a stream linked below another stream based ! 924: * on the multiplexor ID. If the multiplexor ID is -1, then this function ! 925: * returns the first stream found linked below the given upper stream. In ! 926: * addition, the "cmd" value is used to distinguish between the persistent and ! 927: * regular multiplexor ID spaces. ! 928: */ ! 929: ! 930: #if __USE_PROTO__ ! 931: __LOCAL__ shead_t * (SHEAD_FIND_MUXID) (shead_t * upper, int cmd, ! 932: muxid_t muxid) ! 933: #else ! 934: __LOCAL__ shead_t * ! 935: SHEAD_FIND_MUXID __ARGS ((upper, cmd, muxid)) ! 936: shead_t * upper; ! 937: int cmd; ! 938: muxid_t muxid; ! 939: #endif ! 940: { ! 941: shead_t * scan; ! 942: pl_t prev_pl; ! 943: int checklist; ! 944: ! 945: /* ! 946: * Precook "cmd" for easier testing below. ! 947: */ ! 948: ! 949: cmd = (cmd == I_PLINK || cmd == I_PUNLINK) ? SH_PLINK : 0; ! 950: ! 951: ! 952: /* ! 953: * Now take out a lock to protect our list walking. ! 954: */ ! 955: ! 956: prev_pl = RW_RDLOCK (str_mem->sm_head_lock, plstr); ! 957: ! 958: for (checklist = DEV_SLIST ; checklist < SLIST_MAX ; checklist ++) { ! 959: ! 960: for (scan = str_mem->sm_streams [checklist] ; scan != NULL ; ! 961: scan = scan->sh_next) { ! 962: ! 963: if (scan->sh_linked == upper && ! 964: (scan->sh_flags & SH_PLINK) == cmd && ! 965: ((scan->sh_muxid == muxid) || muxid == -1)) { ! 966: ! 967: goto done; ! 968: } ! 969: } ! 970: } ! 971: ! 972: done: ! 973: RW_UNLOCK (str_mem->sm_head_lock, prev_pl); ! 974: ! 975: return scan; ! 976: } ! 977: ! 978: ! 979: /* ! 980: * A local helper function for stream head timeouts. ! 981: */ ! 982: ! 983: #if __USE_PROTO__ ! 984: __LOCAL__ void shead_timer_func (_VOID * arg) ! 985: #else ! 986: __LOCAL__ void ! 987: shead_timer_func (arg) ! 988: _VOID * arg; ! 989: #endif ! 990: { ! 991: shead_t * sheadp = (shead_t *) arg; ! 992: unsigned locks; ! 993: ! 994: SHEAD_ASSERT_LOCKED (sheadp); ! 995: ! 996: SV_BROADCAST (sheadp->sh_wait_sv, 0); ! 997: ! 998: sheadp->sh_lock_mask &= ~ SH_TIMEFLAG; ! 999: sheadp->sh_timeout_id = 0; ! 1000: sheadp->sh_time_count = 0; ! 1001: ! 1002: /* ! 1003: * Note that we advance "sh_time_count" on behalf of the processes ! 1004: * that have the stream head locked. ! 1005: */ ! 1006: ! 1007: locks = sheadp->sh_lock_mask & SH_LOCK_MASK; ! 1008: ! 1009: while (locks != 0) { ! 1010: ! 1011: if ((locks & 1) != 0) ! 1012: sheadp->sh_time_count ++; ! 1013: locks >>= 1; ! 1014: } ! 1015: } ! 1016: ! 1017: ! 1018: /* ! 1019: * This function is called when the time has come to actually initiate a ! 1020: * timeout. ! 1021: */ ! 1022: ! 1023: #if __USE_PROTO__ ! 1024: int (SHEAD_START_TIMEOUT) (shead_t * sheadp) ! 1025: #else ! 1026: int ! 1027: SHEAD_START_TIMEOUT __ARGS ((sheadp)) ! 1028: shead_t * sheadp; ! 1029: #endif ! 1030: { ! 1031: __clock_t the_time; ! 1032: ! 1033: SHEAD_ASSERT_LOCKED (sheadp); ! 1034: ! 1035: if ((sheadp->sh_lock_mask & SH_TIMEFLAG) == 0 || ! 1036: sheadp->sh_timeout_id != 0) ! 1037: return 1; /* do nothing */ ! 1038: ! 1039: (void) drv_getparm (LBOLT, & the_time); ! 1040: ! 1041: sheadp->sh_timeout_id = ltimeout (shead_timer_func, sheadp, ! 1042: sheadp->sh_timeout_tick - the_time, ! 1043: sheadp->sh_basic_lockp, plstr); ! 1044: ! 1045: /* ! 1046: * If the timeout could not be scheduled, we return 0 to indicate to ! 1047: * the caller that it should timeout immediately, and run the timeout ! 1048: * function to fake a normal timeout. ! 1049: */ ! 1050: ! 1051: if (sheadp->sh_timeout_id == 0) { ! 1052: ! 1053: shead_timer_func (sheadp); ! 1054: return 0; ! 1055: } ! 1056: ! 1057: return 1; ! 1058: } ! 1059: ! 1060: ! 1061: /* ! 1062: * Indicate that no timeout will be necessary for this lock item. ! 1063: */ ! 1064: ! 1065: #if __USE_PROTO__ ! 1066: void (SHEAD_NO_TIMEOUT) (shead_t * sheadp) ! 1067: #else ! 1068: void ! 1069: SHEAD_NO_TIMEOUT __ARGS ((sheadp)) ! 1070: shead_t * sheadp; ! 1071: #endif ! 1072: { ! 1073: SHEAD_ASSERT_LOCKED (sheadp); ! 1074: ! 1075: ASSERT (sheadp->sh_time_count < sheadp->sh_lock_count); ! 1076: ! 1077: if (++ sheadp->sh_time_count == sheadp->sh_lock_count) { ! 1078: /* ! 1079: * Since we are the last process to register an end time, we ! 1080: * get to actually initiate a timeout for the stream head. ! 1081: */ ! 1082: ! 1083: (void) SHEAD_START_TIMEOUT (sheadp); ! 1084: } ! 1085: } ! 1086: ! 1087: ! 1088: /* ! 1089: * Indicate that a timeout is desired for this lock item at the given clock ! 1090: * tick. ! 1091: */ ! 1092: ! 1093: #if __USE_PROTO__ ! 1094: int (SHEAD_LOCK_TIMEOUT) (shead_t * sheadp, __clock_t end_time) ! 1095: #else ! 1096: int ! 1097: SHEAD_LOCK_TIMEOUT __ARGS ((sheadp, end_time)) ! 1098: shead_t * sheadp; ! 1099: __clock_t end_time; ! 1100: #endif ! 1101: { ! 1102: __clock_t the_time; ! 1103: ! 1104: SHEAD_ASSERT_LOCKED (sheadp); ! 1105: ! 1106: ASSERT (sheadp->sh_time_count < sheadp->sh_lock_count); ! 1107: ! 1108: ! 1109: /* ! 1110: * If our horizon falls before the current latest value (or if there ! 1111: * is no latest value), select our horizon time. If the horizon time ! 1112: * is *before* the current time, return 0. ! 1113: * ! 1114: * Comparing time values introduces the usual problems when dealing ! 1115: * with sequence spaces in C. While the following expression is not ! 1116: * as efficient as relying on the semantics of unsigned->signed ! 1117: * casting, avoiding implementation-defined behaviour is important. ! 1118: * ! 1119: * "clock_t" MUST be unsigned for this to work. ! 1120: */ ! 1121: ! 1122: ASSERT ((__clock_t) -1 > 0); ! 1123: ! 1124: (void) drv_getparm (LBOLT, & the_time); ! 1125: ! 1126: if ((__clock_t) (the_time - end_time) < ((__clock_t) -1 >> 1)) { ! 1127: /* ! 1128: * The indicated time has already passed, so we return a ! 1129: * timeout indication directly. ! 1130: */ ! 1131: ! 1132: sheadp->sh_time_count ++; ! 1133: return 0; ! 1134: } ! 1135: ! 1136: ! 1137: if ((sheadp->sh_lock_mask & SH_TIMEFLAG) == 0 || ! 1138: (__clock_t) (sheadp->sh_timeout_tick - end_time) < ! 1139: ((__clock_t) -1 >> 1)) { ! 1140: /* ! 1141: * "end_time" will occur before the current latest time. If ! 1142: * a timeout has been scheduled, we cancel it because we want ! 1143: * to post a more recent one. ! 1144: */ ! 1145: ! 1146: if (sheadp->sh_timeout_id != 0) { ! 1147: ! 1148: untimeout (sheadp->sh_timeout_id); ! 1149: sheadp->sh_timeout_id = 0; ! 1150: } ! 1151: ! 1152: sheadp->sh_lock_mask |= SH_TIMEFLAG; ! 1153: } ! 1154: ! 1155: if (++ sheadp->sh_time_count == sheadp->sh_lock_count) { ! 1156: /* ! 1157: * Since we are the last process to register an end time, we ! 1158: * get to actually initiate a timeout for the stream head. ! 1159: */ ! 1160: ! 1161: return SHEAD_START_TIMEOUT (sheadp); ! 1162: } else { ! 1163: /* ! 1164: * We can go to sleep and rely on someone else to actually ! 1165: * intiate the timeout. ! 1166: */ ! 1167: ! 1168: return 1; ! 1169: } ! 1170: } ! 1171: ! 1172: ! 1173: /* ! 1174: * This function is used when a process wants to cancel a timeout after having ! 1175: * registered one. ! 1176: */ ! 1177: ! 1178: #if __USE_PROTO__ ! 1179: void (SHEAD_END_TIMEOUT) (shead_t * sheadp) ! 1180: #else ! 1181: void ! 1182: SHEAD_END_TIMEOUT __ARGS ((sheadp)) ! 1183: shead_t * sheadp; ! 1184: #endif ! 1185: { ! 1186: SHEAD_ASSERT_LOCKED (sheadp); ! 1187: ! 1188: if (sheadp->sh_timeout_id != 0) { ! 1189: ! 1190: ASSERT (sheadp->sh_time_count == sheadp->sh_lock_count + 1); ! 1191: sheadp->sh_time_count --; ! 1192: } ! 1193: } ! 1194: ! 1195: ! 1196: /* ! 1197: * This function is used when a lock holder wishes to sleep waiting for a ! 1198: * timeout. ! 1199: */ ! 1200: ! 1201: #if __USE_PROTO__ ! 1202: int (SHEAD_LOCKED_TIMEOUT) (shead_t * sheadp, __clock_t end_time) ! 1203: #else ! 1204: int ! 1205: SHEAD_LOCKED_TIMEOUT __ARGS ((sheadp, end_time)) ! 1206: shead_t * sheadp; ! 1207: __clock_t end_time; ! 1208: #endif ! 1209: { ! 1210: SHEAD_ASSERT_LOCKED (sheadp); ! 1211: ! 1212: ASSERT (sheadp->sh_time_count > 0); ! 1213: ! 1214: sheadp->sh_time_count --; ! 1215: ! 1216: return SHEAD_LOCK_TIMEOUT (sheadp, end_time); ! 1217: } ! 1218: ! 1219: ! 1220: /* ! 1221: * Common code to test whether a stream has experienced an error condition. ! 1222: */ ! 1223: ! 1224: #define _shead_error(sheadp,mode) \ ! 1225: (SHEAD_ASSERT_LOCKED (sheadp), \ ! 1226: sheadp->sh_linked != NULL ? EINVAL : \ ! 1227: ((mode) & FWRITE) != 0 && sheadp->sh_werrcode != 0 ? \ ! 1228: sheadp->sh_werrcode : \ ! 1229: ((mode) & FREAD) != 0 ? sheadp->sh_rerrcode : 0) ! 1230: ! 1231: /* ! 1232: * This function tests for error or hangup conditions on the stream head given ! 1233: * by "sheadp". It assumes that the caller holds a basic lock on the stream ! 1234: * head. If an error or hangup condition exists then the basic lock is ! 1235: * unlocked and a non-zero error number is returned. ! 1236: */ ! 1237: ! 1238: #if __USE_PROTO__ ! 1239: __LOCAL__ int (SHEAD_ERRHUP_LOCKED) (shead_t * sheadp, int mode) ! 1240: #else ! 1241: __LOCAL__ int ! 1242: SHEAD_ERRHUP_LOCKED __ARGS ((sheadp, mode)) ! 1243: shead_t * sheadp; ! 1244: int mode; ! 1245: #endif ! 1246: { ! 1247: int retval; ! 1248: ! 1249: SHEAD_ASSERT_LOCKED (sheadp); ! 1250: ! 1251: if ((retval = _shead_error (sheadp, mode)) != 0 || ! 1252: ((mode & (FREAD | FWRITE)) != 0 && ! 1253: (retval = ENXIO, SHEAD_HANGUP (sheadp) != 0))) { ! 1254: ! 1255: SHEAD_UNLOCK (sheadp, plbase); ! 1256: return retval; ! 1257: } ! 1258: ! 1259: return 0; ! 1260: } ! 1261: ! 1262: ! 1263: /* ! 1264: * Definitions use for the "interruptible" parameter to SHEAD_WAIT () and ! 1265: * SHEAD_LOCK (). ! 1266: */ ! 1267: ! 1268: enum { ! 1269: DONT_SIGNAL = 0, ! 1270: CHECK_SIGNALS = 1 ! 1271: }; ! 1272: ! 1273: ! 1274: /* ! 1275: * This function is the common interface to waiting for an event at a stream ! 1276: * head. It borrows the same synchronization variable used by the stream head ! 1277: * locking code in this implementation. ! 1278: * ! 1279: * We return 0 on success or an error number on failure. ! 1280: */ ! 1281: ! 1282: #if __USE_PROTO__ ! 1283: __LOCAL__ int (SHEAD_WAIT) (shead_t * sheadp, int mode, cat_t category, ! 1284: int interruptible) ! 1285: #else ! 1286: __LOCAL__ int ! 1287: SHEAD_WAIT __ARGS ((sheadp, mode, category, interruptible)) ! 1288: shead_t * sheadp; ! 1289: int mode; ! 1290: cat_t category; ! 1291: int interruptible; ! 1292: #endif ! 1293: { ! 1294: int retval; ! 1295: ! 1296: SHEAD_ASSERT_LOCKED (sheadp); ! 1297: ! 1298: /* ! 1299: * Test for error/hangup conditions before we sleep. ! 1300: */ ! 1301: ! 1302: if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, mode)) != 0) ! 1303: return retval; ! 1304: ! 1305: /* ! 1306: * Register our interest in the kind of event that we are waiting for. ! 1307: */ ! 1308: ! 1309: sheadp->sh_lock_mask |= category; ! 1310: ! 1311: if (interruptible == CHECK_SIGNALS) ! 1312: return SV_WAIT_SIG (sheadp->sh_wait_sv, primed, ! 1313: sheadp->sh_basic_lockp) == 0 ? EINTR : 0; ! 1314: else { ! 1315: SV_WAIT (sheadp->sh_wait_sv, primed, sheadp->sh_basic_lockp); ! 1316: return 0; ! 1317: } ! 1318: } ! 1319: ! 1320: ! 1321: /* ! 1322: * This function is a slightly different interface to SHEAD_WAIT (), used when ! 1323: * the caller has been examining some property of a queue and wishes to go ! 1324: * to sleep atomically. A frozen queue is not suitable for passing to ! 1325: * SV_WAIT_SIG (), so we acquire the stream head global lock and then unfreeze ! 1326: * the queue on behalf of the caller. This yields correct behaviour because ! 1327: * SHEAD_WAKE () also attempts to acquire the stream head global lock; any ! 1328: * modification to a stream queue resulting in a wakeup request will follow ! 1329: * the same locking sequence. ! 1330: */ ! 1331: ! 1332: #if __USE_PROTO__ ! 1333: __LOCAL__ int (SHEAD_WAIT_NONBLOCK) (shead_t * sheadp, int mode, ! 1334: cat_t category, int interruptible) ! 1335: #else ! 1336: __LOCAL__ int ! 1337: SHEAD_WAIT_NONBLOCK __ARGS ((sheadp, mode, category, interruptible)) ! 1338: shead_t * sheadp; ! 1339: int mode; ! 1340: cat_t category; ! 1341: int interruptible; ! 1342: #endif ! 1343: { ! 1344: SHEAD_ASSERT_LOCKED (sheadp); ! 1345: ! 1346: if ((mode & (FNDELAY | FNONBLOCK)) != 0) { ! 1347: ! 1348: SHEAD_UNLOCK (sheadp, plbase); ! 1349: return EAGAIN; ! 1350: } ! 1351: ! 1352: return SHEAD_WAIT (sheadp, mode, category, interruptible); ! 1353: } ! 1354: ! 1355: ! 1356: /* ! 1357: * This function is used by lower-level code to signal events to functions ! 1358: * that have waited via SHEAD_WAIT (), above. ! 1359: */ ! 1360: ! 1361: #if __USE_PROTO__ ! 1362: void (SHEAD_WAKE) (shead_t * sheadp, cat_t category) ! 1363: #else ! 1364: void ! 1365: SHEAD_WAKE __ARGS ((sheadp, category)) ! 1366: shead_t * sheadp; ! 1367: cat_t category; ! 1368: #endif ! 1369: { ! 1370: pl_t prev_pl; ! 1371: ! 1372: prev_pl = SHEAD_LOCK (sheadp); ! 1373: ! 1374: if ((sheadp->sh_lock_mask & category) != 0) { ! 1375: ! 1376: sheadp->sh_lock_mask &= ~ category; ! 1377: SV_BROADCAST (sheadp->sh_wait_sv, 0); ! 1378: } ! 1379: ! 1380: SHEAD_UNLOCK (sheadp, prev_pl); ! 1381: } ! 1382: ! 1383: ! 1384: /* ! 1385: * Common code for locking stream head, shared between open-style locks (which ! 1386: * may need to allocate new head structures and need special coordination ! 1387: * with the stream head destruction code) and other kinds. ! 1388: * ! 1389: * We expect that the caller will have taken out a basic lock on the stream ! 1390: * head and that the caller will have incremented the lock count of the item ! 1391: * to prevent it from being deallocated while we wait. ! 1392: */ ! 1393: ! 1394: #if __USE_PROTO__ ! 1395: int (SHEAD_SLEEP_LOCKED) (shead_t * sheadp, cat_t category, __clock_t timeout, ! 1396: int interruptible) ! 1397: #else ! 1398: int ! 1399: SHEAD_SLEEP_LOCKED __ARGS ((sheadp, category, timeout, interruptible)) ! 1400: shead_t * sheadp; ! 1401: cat_t category; ! 1402: __clock_t timeout; ! 1403: int interruptible; ! 1404: #endif ! 1405: { ! 1406: __clock_t end_time; /* LBOLT when we time out */ ! 1407: n_dev_t devno; ! 1408: int retval; ! 1409: ! 1410: SHEAD_ASSERT_LOCKED (sheadp); ! 1411: ! 1412: /* ! 1413: * Since we expect the caller to have incremented the lock count, then ! 1414: * the caller must have selected the master end of the stream pipe. ! 1415: */ ! 1416: ! 1417: ASSERT (sheadp == SHEAD_MASTER (sheadp)); ! 1418: ! 1419: /* ! 1420: * If we are going to be (possibly) timing out, calculate the time ! 1421: * when that will happen. ! 1422: */ ! 1423: ! 1424: if (timeout > 0) { ! 1425: ! 1426: (void) drv_getparm (LBOLT, & end_time); ! 1427: end_time += timeout; ! 1428: } ! 1429: ! 1430: ! 1431: /* ! 1432: * There is a special case that we have to note; in the case of a ! 1433: * clone open, the device number of a stream head may be altered by ! 1434: * the driver open routine. In this case, drivers waiting on the old ! 1435: * number will have to be notified and give up on their lock attempts. ! 1436: */ ! 1437: ! 1438: devno = sheadp->sh_dev; ! 1439: ! 1440: ! 1441: /* ! 1442: * Now we begin the actual business of locking the stream head. ! 1443: */ ! 1444: ! 1445: for (;;) { ! 1446: int sigflg; ! 1447: ! 1448: /* ! 1449: * Check to see whether our category is blocked. At this point ! 1450: * we hold "global_lock". ! 1451: * ! 1452: * An earlier verson of this code had an explicit check for ! 1453: * final close. I have no idea why, because if a stream is in ! 1454: * final close, what else can happen? ! 1455: */ ! 1456: ! 1457: if ((sheadp->sh_lock_mask & category) == 0) { ! 1458: /* ! 1459: * We can acquire a lock on the stream head in our ! 1460: * chosen category, so we do so. Since we will not ! 1461: * need a timeout, we increment the timeout count. ! 1462: * ! 1463: * If during later processing we need a timeout, we ! 1464: * hook into this mechanism, but for simplicity we ! 1465: * assume we won't. ! 1466: */ ! 1467: ! 1468: SHEAD_NO_TIMEOUT (sheadp); ! 1469: ! 1470: SHEAD_UNLOCK (sheadp, plbase); ! 1471: ! 1472: sheadp->sh_lock_mask |= category; ! 1473: ! 1474: return 0; ! 1475: } ! 1476: ! 1477: ! 1478: /* ! 1479: * We need to wait, interruptibly. We might also want to time ! 1480: * out at some stage. ! 1481: * ! 1482: * We (optionally) call a function to register the time we ! 1483: * want to expire; this function also takes care of checking ! 1484: * for timeout expiry. ! 1485: */ ! 1486: ! 1487: if (timeout == 0) ! 1488: SHEAD_NO_TIMEOUT (sheadp); ! 1489: else if (SHEAD_LOCK_TIMEOUT (sheadp, end_time) == 0) { ! 1490: /* ! 1491: * Our horizon time has passed, so we return ETIME. ! 1492: */ ! 1493: ! 1494: retval = ETIME; ! 1495: break; ! 1496: } ! 1497: ! 1498: ! 1499: /* ! 1500: * Now we can wait. No matter how we wake up, we will need ! 1501: * to relock the global basic lock. ! 1502: * ! 1503: * The caller may not want this wait to be interruptible; this ! 1504: * is reasonable when the lock is being acquired in some ! 1505: * nested context where things are difficult to back out. ! 1506: */ ! 1507: ! 1508: if (interruptible != DONT_SIGNAL) ! 1509: sigflg = SV_WAIT_SIG (sheadp->sh_wait_sv, primed, ! 1510: sheadp->sh_basic_lockp); ! 1511: else { ! 1512: SV_WAIT (sheadp->sh_wait_sv, primed, ! 1513: sheadp->sh_basic_lockp); ! 1514: sigflg = 1; ! 1515: } ! 1516: ! 1517: (void) SHEAD_LOCK (sheadp); ! 1518: ! 1519: if (sigflg == 0) { ! 1520: /* ! 1521: * We have been interrupted by a signal, so bang out ! 1522: * to the caller with EINTR. ! 1523: */ ! 1524: ! 1525: retval = EINTR; ! 1526: break; ! 1527: } else if (sheadp->sh_dev != devno) { ! 1528: /* ! 1529: * The device number has been altered. Flag the fact ! 1530: * to the caller and give up this lock attempt. ! 1531: */ ! 1532: ! 1533: retval = ENODEV; ! 1534: break; ! 1535: } ! 1536: ! 1537: ! 1538: /* ! 1539: * Now we have the global basic lock, we can wrap around to ! 1540: * the start of the loop to recheck all our conditions. ! 1541: */ ! 1542: } ! 1543: ! 1544: ! 1545: /* ! 1546: * For some reason we are aborting the lock attempt. The code which ! 1547: * make us take this exit path should have set "* retvalp" with an ! 1548: * error code. ! 1549: */ ! 1550: ! 1551: if (sheadp->sh_time_count > sheadp->sh_lock_count) { ! 1552: ! 1553: sheadp->sh_time_count --; ! 1554: ASSERT (sheadp->sh_time_count == sheadp->sh_lock_count); ! 1555: ! 1556: SHEAD_START_TIMEOUT (sheadp); ! 1557: } ! 1558: ! 1559: SHEAD_UNREFERENCE (sheadp); ! 1560: return retval; ! 1561: } ! 1562: ! 1563: ! 1564: /* ! 1565: * Entry point for the stream head locking system for use by routines that ! 1566: * already have a reference to the stream head. This entry performs checks for ! 1567: * routine errors including linked streams. ! 1568: */ ! 1569: ! 1570: #if __USE_PROTO__ ! 1571: int (SHEAD_SLEEP_LOCK) (shead_t * sheadp, cat_t category, __clock_t timeout, ! 1572: int interruptible) ! 1573: #else ! 1574: int ! 1575: SHEAD_SLEEP_LOCK __ARGS ((sheadp, category, timeout, interruptible)) ! 1576: shead_t * sheadp; ! 1577: cat_t category; ! 1578: __clock_t timeout; ! 1579: int interruptible; ! 1580: #endif ! 1581: { ! 1582: SHEAD_LOCK (sheadp); ! 1583: ! 1584: /* ! 1585: * The read and write lock modes are experimental. We have a mode bit ! 1586: * that says whether or not we are really interested in honouring ! 1587: * these lock types. ! 1588: */ ! 1589: ! 1590: if (((sheadp->sh_flags & SH_RWLOCKING) == 0 && ! 1591: (category & ~ (SH_READ_LOCK | SH_WRITE_LOCK)) == 0)) { ! 1592: ! 1593: SHEAD_UNLOCK (sheadp, plbase); ! 1594: return 0; ! 1595: } ! 1596: ! 1597: ! 1598: /* ! 1599: * If the caller wishes to lock a stream head that is part of a stream ! 1600: * pipe, we direct the lock attempt to the master stream head of the ! 1601: * pair that form the pipe. This ensures that any attempt to modify ! 1602: * the state of the pipe from either end will be properly single- ! 1603: * threaded. ! 1604: * ! 1605: * Note that we *must* perform a similar redirection in the unlock. ! 1606: */ ! 1607: ! 1608: sheadp = SHEAD_MASTER (sheadp); ! 1609: ! 1610: ! 1611: /* ! 1612: * We have a pointer to the stream head and hold a global basic lock. ! 1613: * ! 1614: * With the protection of the basic lock, we increment the lock count. ! 1615: */ ! 1616: ! 1617: sheadp->sh_lock_count ++; ! 1618: ! 1619: /* ! 1620: * Now we begin the actual business of locking the stream head. ! 1621: */ ! 1622: ! 1623: return SHEAD_SLEEP_LOCKED (sheadp, category, timeout, interruptible); ! 1624: } ! 1625: ! 1626: ! 1627: /* ! 1628: * This is a special form of the stream head locking code for open () access, ! 1629: * which specially coordinates with the close code to discover when to ! 1630: * allocate a new stream head, and carefully avoids the problems that can ! 1631: * occur if the stream head were to be deallocated which we are waiting for ! 1632: * it to be unlocked. ! 1633: * ! 1634: * We also have to do some funky stuff here because of clone opens. ! 1635: */ ! 1636: ! 1637: #if __USE_PROTO__ ! 1638: shead_t * (SHEAD_OPEN_LOCK) (n_dev_t dev, struct streamtab * stabp, ! 1639: int * retvalp) ! 1640: #else ! 1641: shead_t * ! 1642: SHEAD_OPEN_LOCK __ARGS ((dev, stabp, retvalp)) ! 1643: n_dev_t dev; ! 1644: struct streamtab ! 1645: * stabp; ! 1646: int * retvalp; ! 1647: #endif ! 1648: { ! 1649: shead_t * sheadp; ! 1650: ! 1651: ASSERT (retvalp != NULL); ! 1652: ! 1653: /* ! 1654: * PHASE 1: Locate the stream head. If the stream head did not ! 1655: * previously exist, we might be able to lock it immediately by virtue ! 1656: * of being able to create it that way. Of course, simultaneous open ! 1657: * attempts might result in this looping as only once of the created ! 1658: * stream heads will be entered in the stream directory. ! 1659: */ ! 1660: ! 1661: * retvalp = 0; ! 1662: ! 1663: for (;;) { ! 1664: queue_t * q; ! 1665: ! 1666: /* ! 1667: * The first thing we need to do is *find* the stream. We call ! 1668: * a find routine that increments a reference count so that ! 1669: * we can be sure that the stream will not be deallocated ! 1670: * while we wait. ! 1671: */ ! 1672: ! 1673: if ((sheadp = SHEAD_FIND_AND_LOCK (dev, DEV_SLIST)) != NULL) { ! 1674: /* ! 1675: * Sleep lock time; our call to SHEAD_FIND_AND_LOCK () ! 1676: * will have incremented the lock count of the stream ! 1677: * head so it won't disappear underneath us. ! 1678: */ ! 1679: ! 1680: * retvalp = SHEAD_SLEEP_LOCKED (sheadp, SH_OPENCLOSE, ! 1681: 0, CHECK_SIGNALS); ! 1682: ! 1683: if (retvalp != 0) { ! 1684: /* ! 1685: * If the lock attempt failed because of a ! 1686: * clone open changing the stream head's ! 1687: * device number, we need to try again. ! 1688: */ ! 1689: ! 1690: sheadp = NULL; ! 1691: ! 1692: if (* retvalp == ENODEV) ! 1693: continue; ! 1694: } ! 1695: ! 1696: return sheadp; ! 1697: } ! 1698: ! 1699: ! 1700: /* ! 1701: * There ain't no such stream, so we have to allocate a queue ! 1702: * pair. ! 1703: */ ! 1704: ! 1705: if ((q = QUEUE_ALLOC (2, sizeof (* sheadp))) == NULL) { ! 1706: ! 1707: * retvalp = ENFILE; ! 1708: return NULL; ! 1709: } ! 1710: ! 1711: sheadp = (shead_t *) q->q_ptr; ! 1712: ! 1713: SHEAD_INIT (sheadp, stabp, dev, q); ! 1714: ! 1715: sheadp->sh_ref_count = 1; ! 1716: sheadp->sh_lock_mask = SH_OPENCLOSE; ! 1717: sheadp->sh_time_count = sheadp->sh_lock_count = 1; ! 1718: ! 1719: if (SHEAD_ADD (sheadp) == 0) ! 1720: return sheadp; ! 1721: ! 1722: /* ! 1723: * The new queue could not be added to the stream ! 1724: * directory, presumably because of a nearly ! 1725: * simultaneous open attempt. ! 1726: * ! 1727: * We undo the allocation we wrought before retrying. ! 1728: */ ! 1729: ! 1730: SHEAD_DESTROY (sheadp); ! 1731: QUEUE_FREE (q, 2, sizeof (* sheadp)); ! 1732: } ! 1733: } ! 1734: ! 1735: ! 1736: /* ! 1737: * Unlock a stream head. ! 1738: */ ! 1739: ! 1740: #if __USE_PROTO__ ! 1741: void (SHEAD_SLEEP_UNLOCK) (shead_t * sheadp, cat_t category) ! 1742: #else ! 1743: void ! 1744: SHEAD_SLEEP_UNLOCK __ARGS ((sheadp, category)) ! 1745: shead_t * sheadp; ! 1746: cat_t category; ! 1747: #endif ! 1748: { ! 1749: ASSERT (sheadp != NULL); ! 1750: ASSERT (category != 0); ! 1751: ! 1752: /* ! 1753: * See if locking is necessary for the read and write operations. ! 1754: */ ! 1755: ! 1756: if ((sheadp->sh_flags & SH_RWLOCKING) == 0 && ! 1757: (category & ~ (SH_READ_LOCK | SH_WRITE_LOCK)) == 0) { ! 1758: /* ! 1759: * Since we don't actually acquire any locks, we return early. ! 1760: */ ! 1761: ! 1762: ASSERT (sheadp->sh_open_count > 0); ! 1763: return; ! 1764: } ! 1765: ! 1766: ASSERT (sheadp->sh_lock_count > 0); ! 1767: ASSERT ((sheadp->sh_lock_mask & category) == category); ! 1768: ! 1769: ! 1770: /* ! 1771: * We direct all locking operations on the slave part of a stream pipe ! 1772: * to the master end. ! 1773: */ ! 1774: ! 1775: sheadp = SHEAD_MASTER (sheadp); ! 1776: ! 1777: (void) SHEAD_LOCK (sheadp); ! 1778: ! 1779: ! 1780: /* ! 1781: * Unlike SHEAD_WAKE (), we can assume that our category mask will not ! 1782: * be NULL because of the difference in interpretation between lock ! 1783: * flags (indicating a holder) and wait flags (indicating a waiter). ! 1784: */ ! 1785: ! 1786: sheadp->sh_lock_mask &= ~ category; ! 1787: SV_BROADCAST (sheadp->sh_wait_sv, 0); ! 1788: ! 1789: ! 1790: /* ! 1791: * We don't use SHEAD_END_TIMEOUT () here since we are a lock holder ! 1792: * and shead_time_func () makes sure to keep our "sh_time_count" entry ! 1793: * greater than 0. ! 1794: */ ! 1795: ! 1796: ASSERT (sheadp->sh_time_count > 0); ! 1797: sheadp->sh_time_count --; ! 1798: ! 1799: if (sheadp->sh_time_count == 0 && sheadp->sh_timeout_id != 0) { ! 1800: /* ! 1801: * Since there is no-one waiting for anything, cancel any ! 1802: * pending timeouts. ! 1803: */ ! 1804: ! 1805: untimeout (sheadp->sh_timeout_id); ! 1806: ! 1807: sheadp->sh_lock_mask &= SH_TIMEFLAG; ! 1808: sheadp->sh_timeout_id = 0; ! 1809: } ! 1810: ! 1811: ! 1812: /* ! 1813: * Now that we have done everything that requires access to the stream ! 1814: * head, decrement the lock count. ! 1815: */ ! 1816: ! 1817: SHEAD_UNREFERENCE (sheadp); ! 1818: } ! 1819: ! 1820: ! 1821: /* ! 1822: * This local function asserts that the caller holds a lock on the stream head. ! 1823: * Since we can't really determine that, we actually just assert that someone ! 1824: * has a lock on the stream head. ! 1825: */ ! 1826: ! 1827: #if __USE_PROTO__ ! 1828: __LOCAL__ void (ASSERT_SLEEP_LOCKED) (shead_t * sheadp, cat_t category) ! 1829: #else ! 1830: __LOCAL__ void ! 1831: ASSERT_SLEEP_LOCKED __ARGS ((sheadp, category)) ! 1832: shead_t * sheadp; ! 1833: cat_t category; ! 1834: #endif ! 1835: { ! 1836: ASSERT (sheadp != NULL); ! 1837: ! 1838: if (SHEAD_IS_PIPE (sheadp)) ! 1839: sheadp = SHEAD_MASTER (sheadp); ! 1840: ! 1841: ASSERT ((sheadp->sh_lock_mask & category) == category); ! 1842: } ! 1843: ! 1844: ! 1845: /* ! 1846: * Wait for a queue to drain. The caller must have the stream head locked when ! 1847: * calling this function. ! 1848: */ ! 1849: ! 1850: #if __USE_PROTO__ ! 1851: __LOCAL__ void (DRAIN_QUEUE) (shead_t * sheadp, queue_t * q) ! 1852: #else ! 1853: __LOCAL__ void ! 1854: DRAIN_QUEUE __ARGS ((sheadp, q)) ! 1855: shead_t * sheadp; ! 1856: queue_t * q; ! 1857: #endif ! 1858: { ! 1859: __clock_t end_time; ! 1860: ! 1861: ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE); ! 1862: ! 1863: /* ! 1864: * When we are in final close, the STREAMS specification says we ! 1865: * should wait for up to 15 seconds for the write-side queue to be ! 1866: * drained of data, unless we are in O_NONBLOCK mode. ! 1867: * ! 1868: * If we can't post the timeout, then don't wait. ! 1869: */ ! 1870: ! 1871: if (sheadp->sh_cltime == 0) ! 1872: return; ! 1873: ! 1874: (void) drv_getparm (LBOLT, & end_time); ! 1875: end_time += sheadp->sh_cltime; ! 1876: ! 1877: for (;;) { ! 1878: /* ! 1879: * We need to acquire a basic lock to pass to SV_WAIT (), and ! 1880: * the code that wakes us up will attempt to acquire the same ! 1881: * lock (see QUEUE_DRAINED ()). Since the wakeup code must ! 1882: * acquire the lock while holding the stream frozen, we must ! 1883: * do things in the same order to prevent the possibility of ! 1884: * deadlock. ! 1885: */ ! 1886: ! 1887: (void) QFREEZE_TRACE (q, "DRAIN_QUEUE"); ! 1888: ! 1889: if (q->q_first == NULL) { ! 1890: /* ! 1891: * No messages on the queue => our job is done. ! 1892: */ ! 1893: ! 1894: QUNFREEZE_TRACE (q, plbase); ! 1895: break; ! 1896: } ! 1897: ! 1898: ! 1899: /* ! 1900: * We are going to wait for this queue to become empty, so we ! 1901: * set a flag to indicate that we are interested in finding ! 1902: * out when that happens. Note that we don't ever clear the ! 1903: * flag in this routine; that is the responsibility of the ! 1904: * code which will wake us up. ! 1905: */ ! 1906: ! 1907: q->q_flag |= QDRAIN; ! 1908: ! 1909: ! 1910: /* ! 1911: * We don't build on SHEAD_WAIT (), although we do expect to ! 1912: * be woken up via SHEAD_WAKE (). We transfer our lock from ! 1913: * the queue to the stream head. ! 1914: */ ! 1915: ! 1916: (void) SHEAD_LOCK (sheadp); ! 1917: ! 1918: QUNFREEZE_TRACE (q, plstr); ! 1919: ! 1920: ! 1921: /* ! 1922: * Register when we want to time out. If that time has already ! 1923: * passed, then exit to the caller. ! 1924: */ ! 1925: ! 1926: if (SHEAD_LOCKED_TIMEOUT (sheadp, end_time) == 0) { ! 1927: ! 1928: SHEAD_UNLOCK (sheadp, plbase); ! 1929: return; ! 1930: } ! 1931: ! 1932: sheadp->sh_lock_mask |= SH_DRAIN_WAIT; ! 1933: ! 1934: SV_WAIT (sheadp->sh_wait_sv, primed, sheadp->sh_basic_lockp); ! 1935: ! 1936: /* ! 1937: * We were signalled, so we try again. ! 1938: */ ! 1939: } ! 1940: } ! 1941: ! 1942: ! 1943: /* ! 1944: * This function (used in the implementation of I_LIST ioctl ()) returns a ! 1945: * count of the number of modules on the stream, including the topmost driver. ! 1946: */ ! 1947: ! 1948: #if __USE_PROTO__ ! 1949: __LOCAL__ int (SHEAD_MODCOUNT) (shead_t * sheadp) ! 1950: #else ! 1951: __LOCAL__ int ! 1952: SHEAD_MODCOUNT __ARGS ((sheadp)) ! 1953: shead_t * sheadp; ! 1954: #endif ! 1955: { ! 1956: pl_t prev_pl; ! 1957: int count; ! 1958: queue_t * scan; ! 1959: ! 1960: ASSERT (sheadp != NULL); ! 1961: ! 1962: /* ! 1963: * Note that we use SHEAD_MASTER () because this walk can be affected ! 1964: * by attempts to push or pop queues from either end of a stream pipe. ! 1965: * Using a single lock at the master end avoids problems with this. ! 1966: */ ! 1967: ! 1968: prev_pl = SHEAD_LOCK (SHEAD_MASTER (sheadp)); ! 1969: ! 1970: count = 0; ! 1971: ! 1972: for (scan = W (sheadp->sh_head)->q_next ; scan != NULL ; ! 1973: scan = scan->q_next) { ! 1974: ! 1975: if ((scan->q_flag & QPROCSOFF) == 0) ! 1976: count ++; ! 1977: } ! 1978: ! 1979: SHEAD_UNLOCK (SHEAD_MASTER (sheadp), prev_pl); ! 1980: ! 1981: return count; ! 1982: } ! 1983: ! 1984: ! 1985: /* ! 1986: * Utility routine to return the next write queue below the stream head. This ! 1987: * routine deals with locking the stream head for the duration of the walk and ! 1988: * also check whether the queue has been disabled with qprocsoff (). ! 1989: */ ! 1990: ! 1991: #if __USE_PROTO__ ! 1992: __LOCAL__ queue_t * (TOP_QUEUE) (shead_t * sheadp) ! 1993: #else ! 1994: __LOCAL__ queue_t * ! 1995: TOP_QUEUE __ARGS ((sheadp)) ! 1996: shead_t * sheadp; ! 1997: #endif ! 1998: { ! 1999: pl_t prev_pl; ! 2000: queue_t * scan; ! 2001: ! 2002: ASSERT (sheadp != NULL); ! 2003: ! 2004: /* ! 2005: * Note that we use SHEAD_MASTER () because this walk can be affected ! 2006: * by attempts to push or pop queues from either end of a stream pipe. ! 2007: * Using a single lock at the master end avoids problems with this. ! 2008: */ ! 2009: ! 2010: prev_pl = SHEAD_LOCK (SHEAD_MASTER (sheadp)); ! 2011: ! 2012: scan = W (sheadp->sh_head)->q_next; ! 2013: ! 2014: while ((scan->q_flag & QPROCSOFF) != 0) ! 2015: if ((scan = scan->q_next) == NULL) ! 2016: cmn_err (CE_PANIC, "Off end of stream in TOP_QUEUE ()"); ! 2017: ! 2018: SHEAD_UNLOCK (SHEAD_MASTER (sheadp), prev_pl); ! 2019: ! 2020: return scan; ! 2021: } ! 2022: ! 2023: ! 2024: /* ! 2025: * Utility routine for POP_MODULE () and the I_LOOK processing code that finds ! 2026: * the queue entry for the first module on the stream (if any). ! 2027: */ ! 2028: ! 2029: #if __USE_PROTO__ ! 2030: __LOCAL__ queue_t * (TOP_MODULE) (shead_t * sheadp) ! 2031: #else ! 2032: __LOCAL__ queue_t * ! 2033: TOP_MODULE __ARGS ((sheadp)) ! 2034: shead_t * sheadp; ! 2035: #endif ! 2036: { ! 2037: queue_t * scan; /* module queue */ ! 2038: ! 2039: /* ! 2040: * We return the queue pointer if and only if the thing below the ! 2041: * stream head is a module (not a driver) AND the module's read and ! 2042: * write queues are not interchanged (as they would be at the ! 2043: * crossover point of a STREAMS-based FIFO). ! 2044: */ ! 2045: ! 2046: scan = TOP_QUEUE (sheadp); ! 2047: ! 2048: if ((scan->q_flag & QREADR) != ! 2049: (W (sheadp->sh_head)->q_flag & QREADR)) ! 2050: return NULL; ! 2051: ! 2052: /* ! 2053: * The test to see whether "scan" is a module or driver does not need ! 2054: * to involve QUEUE_NEXT (), since the exact value of 'q->q_next' ! 2055: * isn't important to us, just whether or not it's NULL. ! 2056: */ ! 2057: ! 2058: { ! 2059: pl_t prev_pl; ! 2060: queue_t * next; ! 2061: ! 2062: prev_pl = QFREEZE_TRACE (scan, "TOP_MODULE"); ! 2063: ! 2064: next = scan->q_next; ! 2065: ! 2066: QUNFREEZE_TRACE (scan, prev_pl); ! 2067: ! 2068: if (next == NULL) ! 2069: return NULL; ! 2070: } ! 2071: ! 2072: return R (scan); ! 2073: } ! 2074: ! 2075: ! 2076: /* ! 2077: * Code common to both POP_MODULE () and PUSH_MODULE () for removing and ! 2078: * deallocating a queue pair from a stream. ! 2079: */ ! 2080: ! 2081: #if __USE_PROTO__ ! 2082: __LOCAL__ void (POP_AND_FREE) (shead_t * sheadp, queue_t * module) ! 2083: #else ! 2084: __LOCAL__ void ! 2085: POP_AND_FREE __ARGS ((sheadp, module)) ! 2086: shead_t * sheadp; ! 2087: queue_t * module; ! 2088: #endif ! 2089: { ! 2090: pl_t prev_pl; ! 2091: pl_t q_pl; ! 2092: queue_t * next; ! 2093: ! 2094: ! 2095: /* ! 2096: * Now we must unlink the module queue from the stream. To do this, we ! 2097: * freeze each queue before we change it. However, that is not enough ! 2098: * if we are on a stream pipe, since the stream head at the other end ! 2099: * of the pipe could be trying to modify the same stream, and thus the ! 2100: * same queue pointers that we are going to change. ! 2101: * ! 2102: * We work our way around this by defining a master/slave relationship ! 2103: * between the ends of a pipe, and requiring that the slave end ! 2104: * acquire an exclusive lock on the "sh_rwlockp" lock belonging to the ! 2105: * master. Since the master and slave contend for the same lock, we ! 2106: * can be confident no other concurrent modifications to the stream ! 2107: * are possible. ! 2108: */ ! 2109: ! 2110: prev_pl = SHEAD_LOCK (SHEAD_MASTER (sheadp)); ! 2111: ! 2112: next = W (sheadp->sh_head); ! 2113: ! 2114: ASSERT (next->q_next == W (module)); ! 2115: ! 2116: q_pl = QFREEZE_TRACE (next, "POP_AND_FREE"); ! 2117: next->q_next = W (module)->q_next; ! 2118: QUNFREEZE_TRACE (next, q_pl); ! 2119: ! 2120: ! 2121: next = OTHERQ (next->q_next); ! 2122: ! 2123: ASSERT (next->q_next == module); ! 2124: ! 2125: q_pl = QFREEZE_TRACE (next, "POP_AND_FREE"); ! 2126: next->q_next = sheadp->sh_head; ! 2127: QUNFREEZE_TRACE (next, q_pl); ! 2128: ! 2129: ! 2130: SHEAD_UNLOCK (SHEAD_MASTER (sheadp), prev_pl); ! 2131: ! 2132: ! 2133: /* ! 2134: * Now we can de-initialize the queue pair and free the memory. ! 2135: */ ! 2136: ! 2137: QUEUE_FREE (module, 1, 0); ! 2138: } ! 2139: ! 2140: ! 2141: /* ! 2142: * Pop a module from a stream. In order to request this, the caller must have ! 2143: * the stream head sleep-locked for modification (see SHEAD_SLEEP_LOCK () ! 2144: * above). ! 2145: * ! 2146: * Returns 0 on success or an error number on failure. ! 2147: */ ! 2148: ! 2149: #if __USE_PROTO__ ! 2150: int (POP_MODULE) (shead_t * sheadp, queue_t * q, int mode, cred_t * credp) ! 2151: #else ! 2152: int ! 2153: POP_MODULE __ARGS ((sheadp, q, mode, credp)) ! 2154: shead_t * sheadp; ! 2155: queue_t * q; ! 2156: int mode; ! 2157: cred_t * credp; ! 2158: #endif ! 2159: { ! 2160: int retval; ! 2161: ! 2162: ASSERT (q != NULL); ! 2163: ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE); ! 2164: ! 2165: /* ! 2166: * When a module is popped, it is blown away. If the module needs to ! 2167: * be drained first (as in final close) then the caller has to do it. ! 2168: */ ! 2169: ! 2170: retval = (* q->q_qinfo->qi_qclose) (q, mode, credp); ! 2171: ! 2172: if (retval != 0) ! 2173: cmn_err (CE_WARN, "module close returned %d in POP_MODULE", ! 2174: retval); ! 2175: ! 2176: /* ! 2177: * In case the module didn't turn off put and service routines. ! 2178: */ ! 2179: ! 2180: if ((q->q_flag & QPROCSOFF) == 0) { ! 2181: ! 2182: cmn_err (CE_WARN, "Module %s did not call qprocsoff ()", ! 2183: q->q_qinfo->qi_minfo->mi_idname); ! 2184: qprocsoff (q); ! 2185: } ! 2186: ! 2187: ! 2188: /* ! 2189: * And now we can release the module. We do this whether or not the ! 2190: * caller returned an error. ! 2191: */ ! 2192: ! 2193: POP_AND_FREE (sheadp, q); ! 2194: ! 2195: return retval; ! 2196: } ! 2197: ! 2198: ! 2199: /* ! 2200: * This function pushes the indicated module onto a stream. The caller must ! 2201: * have the stream head sleep-locked for modification. ! 2202: */ ! 2203: ! 2204: #if __USE_PROTO__ ! 2205: int (PUSH_MODULE) (shead_t * sheadp, int mode, cred_t * credp, ! 2206: modsw_t * module) ! 2207: #else ! 2208: int ! 2209: PUSH_MODULE __ARGS ((sheadp, mode, credp, module)) ! 2210: shead_t * sheadp; ! 2211: int mode; ! 2212: cred_t * credp; ! 2213: modsw_t * module; ! 2214: #endif ! 2215: { ! 2216: queue_t * q; ! 2217: queue_t * prev; ! 2218: pl_t prev_pl; ! 2219: pl_t q_pl; ! 2220: int retval; ! 2221: n_dev_t dev; ! 2222: char * modname; ! 2223: ! 2224: ASSERT (module != NULL); ! 2225: ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE); ! 2226: ! 2227: if ((q = QUEUE_ALLOC (1, 0)) == NULL) ! 2228: return ENOSR; ! 2229: ! 2230: QUEUE_INIT (q, module->mod_stream, QI_NORMAL); ! 2231: ! 2232: /* ! 2233: * First we have to link the module into the stream. The newly ! 2234: * allocated queues will have the QPROCSOFF flag set so that they are ! 2235: * ignored by other stream elements until the new module has been ! 2236: * opened. ! 2237: * ! 2238: * As above in POP_MODULE (), we acquire a write lock on the stream ! 2239: * head, which must be a master end if a stream pipe. ! 2240: */ ! 2241: ! 2242: prev_pl = SHEAD_LOCK (SHEAD_MASTER (sheadp)); ! 2243: ! 2244: prev = W (sheadp->sh_head); ! 2245: W (q)->q_next = prev->q_next; ! 2246: ! 2247: q_pl = QFREEZE_TRACE (prev, "PUSH_MODULE"); ! 2248: prev->q_next = W (q); ! 2249: QUNFREEZE_TRACE (prev, q_pl); ! 2250: ! 2251: prev = OTHERQ (W (q)->q_next); ! 2252: q->q_next = sheadp->sh_head; ! 2253: ! 2254: ASSERT (prev->q_next == sheadp->sh_head); ! 2255: ! 2256: q_pl = QFREEZE_TRACE (prev, "PUSH_MODULE"); ! 2257: prev->q_next = q; ! 2258: QUNFREEZE_TRACE (prev, q_pl); ! 2259: ! 2260: SHEAD_UNLOCK (SHEAD_MASTER (sheadp), prev_pl); ! 2261: ! 2262: ! 2263: /* ! 2264: * Ask the module to set itself up. ! 2265: */ ! 2266: ! 2267: dev = sheadp->sh_dev; ! 2268: ! 2269: retval = (* q->q_qinfo->qi_qopen) (q, & dev, mode, MODOPEN, ! 2270: credp); ! 2271: ! 2272: modname = q->q_qinfo->qi_minfo->mi_idname; ! 2273: ! 2274: if (dev != sheadp->sh_dev) ! 2275: cmn_err (CE_WARN, "Module \"%s\" altered its \"dev\" parameter", ! 2276: modname); ! 2277: ! 2278: if (retval != 0) { ! 2279: /* ! 2280: * OK, don't really open this. The module should not have ! 2281: * turned on it's put and service routines. ! 2282: */ ! 2283: ! 2284: if ((q->q_flag & QPROCSOFF) == 0) { ! 2285: ! 2286: cmn_err (CE_WARN, "PUSH_MODULE () : Module %s enabled queue!", ! 2287: modname); ! 2288: qprocson (q); ! 2289: } ! 2290: ! 2291: POP_AND_FREE (sheadp, q); ! 2292: } else if ((q->q_flag & QPROCSOFF) != 0) { ! 2293: ! 2294: cmn_err (CE_WARN, "PUSH_MODULE () : Module %s did not enable queue!", ! 2295: modname); ! 2296: qprocson (q); ! 2297: } ! 2298: ! 2299: return retval; ! 2300: } ! 2301: ! 2302: ! 2303: /* ! 2304: * This function sends an IOCTL message downstream, then blocks until either ! 2305: * a reply arrives at the stream head, the (optional) timeout has expired, or ! 2306: * a signal is received. ! 2307: * ! 2308: * The caller must have the stream head locked for ioctl () processing. ! 2309: */ ! 2310: ! 2311: #if __USE_PROTO__ ! 2312: mblk_t * (IOCTL_SEND) (shead_t * sheadp, int mode, mblk_t * msg, ! 2313: int * errretp, __clock_t timeout_time) ! 2314: #else ! 2315: mblk_t * ! 2316: IOCTL_SEND __ARGS ((sheadp, mode, msg, errretp, timeout_time)) ! 2317: shead_t * sheadp; ! 2318: int mode; ! 2319: mblk_t * msg; ! 2320: int * errretp; ! 2321: __clock_t timeout_time; ! 2322: #endif ! 2323: { ! 2324: __clock_t end_time; ! 2325: int retval; ! 2326: ! 2327: ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK); ! 2328: ASSERT (errretp != NULL); ! 2329: ASSERT (msg != NULL); ! 2330: ! 2331: /* ! 2332: * Set the optional timeout up first. If the timeout cannot be ! 2333: * allocated, we have to return failure. ! 2334: */ ! 2335: ! 2336: if (timeout_time > 0) { ! 2337: ! 2338: (void) drv_getparm (LBOLT, & end_time); ! 2339: end_time += timeout_time; ! 2340: } ! 2341: ! 2342: ! 2343: /* ! 2344: * Now send the client's message downstream. We queue the message on ! 2345: * the write queue rather than directly putting it to avoid the ! 2346: * possibility of deadlock if an acknowledgement is sent back to us ! 2347: * while we are holding the basic lock below. ! 2348: * ! 2349: * We also have to check for the possibility that an error has occurred ! 2350: * on the stream. ! 2351: */ ! 2352: ! 2353: (void) SHEAD_LOCK (sheadp); ! 2354: ! 2355: for (;;) { ! 2356: if (sheadp->sh_ioc_msg != NULL) { ! 2357: /* ! 2358: * If there is some stale ioctl () message lying ! 2359: * around, dispose of it. ! 2360: */ ! 2361: ! 2362: freemsg (sheadp->sh_ioc_msg); ! 2363: sheadp->sh_ioc_msg = NULL; ! 2364: } ! 2365: ! 2366: if (msg != NULL) ! 2367: putq (W (sheadp->sh_head), msg); ! 2368: ! 2369: msg = NULL; ! 2370: ! 2371: ! 2372: /* ! 2373: * Before we go to sleep, we schedule our timeout. ! 2374: */ ! 2375: ! 2376: if (timeout_time > 0 && ! 2377: SHEAD_LOCKED_TIMEOUT (sheadp, end_time) == 0) { ! 2378: /* ! 2379: * We have timed out. ! 2380: */ ! 2381: ! 2382: retval = ETIME; ! 2383: break; ! 2384: } ! 2385: ! 2386: ! 2387: if (sheadp->sh_open_count == 0) { ! 2388: /* ! 2389: * This is a kernel-generated ioctl () and signalling ! 2390: * is not allowed to interrupt us. We pass a NULL mode ! 2391: * to avoid detecting errors. ! 2392: */ ! 2393: ! 2394: ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE); ! 2395: ! 2396: retval = SHEAD_WAIT (sheadp, 0, SH_IOCTL_WAIT, ! 2397: DONT_SIGNAL); ! 2398: } else { ! 2399: /* ! 2400: * SHEAD_WAIT () checks for hangups as well, if the ! 2401: * mode includes read or write. ! 2402: */ ! 2403: ! 2404: ASSERT ((mode & (FREAD | FWRITE)) != 0); ! 2405: ! 2406: retval = SHEAD_WAIT (sheadp, mode, SH_IOCTL_WAIT, ! 2407: CHECK_SIGNALS); ! 2408: } ! 2409: ! 2410: ! 2411: /* ! 2412: * We take out the basic lock here again so we can read ! 2413: * "sheadp->sh_ioc_msg" atomically. ! 2414: */ ! 2415: ! 2416: (void) SHEAD_LOCK (sheadp); ! 2417: ! 2418: msg = sheadp->sh_ioc_msg; ! 2419: sheadp->sh_ioc_msg = NULL; ! 2420: ! 2421: if (retval != 0 || msg != NULL) ! 2422: break; ! 2423: ! 2424: /* ! 2425: * We have been woken up either by a timeout, or for some ! 2426: * activity at the stream head not related to us. We loop to ! 2427: * deal with this. ! 2428: */ ! 2429: } ! 2430: ! 2431: if (retval != 0) { ! 2432: ! 2433: if (errretp != NULL) ! 2434: * errretp = retval; ! 2435: ! 2436: if (msg != NULL) ! 2437: freemsg (msg); ! 2438: ! 2439: msg = NULL; ! 2440: } ! 2441: ! 2442: SHEAD_UNLOCK (sheadp, plbase); ! 2443: ! 2444: return msg; ! 2445: } ! 2446: ! 2447: ! 2448: /* ! 2449: * This function manages transparent ioctl () processing; it sets itself up ! 2450: * to service M_COPYIN and M_COPYOUT requests from a driver until it sees an ! 2451: * M_IOCACK or M_IOCNAK. ! 2452: */ ! 2453: ! 2454: typedef union { ! 2455: struct iocblk ioc; ! 2456: struct copyreq req; ! 2457: struct copyresp resp; ! 2458: } x_ioc_t; ! 2459: ! 2460: #if __USE_PROTO__ ! 2461: __LOCAL__ int (TRANSPARENT_IOCTL) (shead_t * sheadp, int mode, int cmd, ! 2462: _VOID * arg, cred_t * credp, int * rvalp) ! 2463: #else ! 2464: __LOCAL__ int ! 2465: TRANSPARENT_IOCTL __ARGS ((sheadp, mode, cmd, arg, credp, rvalp)) ! 2466: shead_t * sheadp; ! 2467: int mode; ! 2468: int cmd; ! 2469: _VOID * arg; ! 2470: cred_t * credp; ! 2471: int * rvalp; ! 2472: #endif ! 2473: { ! 2474: mblk_t * msg; ! 2475: mblk_t * data; ! 2476: int retval; ! 2477: x_ioc_t * ioc; ! 2478: ! 2479: ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK); ! 2480: ! 2481: /* ! 2482: * The message block allocated for a transparent ioctl () must be ! 2483: * large enough to hold any of the ioctl-related message types so that ! 2484: * modules and drivers (and the stream head) can just change the ! 2485: * message type to reply to a message. ! 2486: */ ! 2487: ! 2488: if ((msg = MSGB_ALLOC (sizeof (* ioc), BPRI_LO, KM_SLEEP)) == NULL) ! 2489: return ENOSR; ! 2490: ! 2491: ioc = (x_ioc_t *) msg->b_rptr; ! 2492: msg->b_wptr = (unsigned char *) (ioc + 1); ! 2493: ! 2494: msg->b_datap->db_type = M_IOCTL; ! 2495: ! 2496: ioc->ioc.ioc_cmd = cmd; ! 2497: ioc->ioc.ioc_cr = credp; ! 2498: ioc->ioc.ioc_id = ++ sheadp->sh_ioc_seq; ! 2499: ioc->ioc.ioc_count = TRANSPARENT; ! 2500: ioc->ioc.ioc_rval = ioc->ioc.ioc_error = 0; ! 2501: ! 2502: ! 2503: /* ! 2504: * A transparent ioctl () gets a single data block containing the ! 2505: * value of "arg". ! 2506: */ ! 2507: ! 2508: if ((data = MSGB_ALLOC (sizeof (arg), BPRI_LO, KM_SLEEP)) == NULL) { ! 2509: ! 2510: retval = ENOSR; ! 2511: goto done; ! 2512: } ! 2513: ! 2514: * (_VOID **) data->b_rptr = arg; ! 2515: data->b_wptr += sizeof (arg); ! 2516: ! 2517: ! 2518: for (;;) { ! 2519: /* ! 2520: * Now we send the ioctl () and wait for the acknowledgement. ! 2521: * Transparent ioctl ()'s wait forever, but M_ERROR and ! 2522: * hangup events are interesting to us, so we can blow out. ! 2523: */ ! 2524: ! 2525: if ((msg = IOCTL_SEND (sheadp, mode, msg, & retval, ! 2526: 0)) == NULL) ! 2527: return retval; ! 2528: ! 2529: ! 2530: /* ! 2531: * Transparent ioctl ()'s dont have to worry about data coming ! 2532: * back in the M_IOCACK message, they just have to process the ! 2533: * M_COPYIN and M_COPYOUT requests. ! 2534: */ ! 2535: ! 2536: switch (msg->b_datap->db_type) { ! 2537: ! 2538: case M_IOCNAK: ! 2539: retval = ioc->ioc.ioc_error; ! 2540: goto done; ! 2541: ! 2542: case M_IOCACK: ! 2543: * rvalp = ioc->ioc.ioc_rval; ! 2544: retval = ioc->ioc.ioc_error; ! 2545: ! 2546: if (ioc->ioc.ioc_count > 0) ! 2547: cmn_err (CE_WARN, "Transparent ioctl () processing forbids data in M_IOCACK"); ! 2548: goto done; ! 2549: ! 2550: case M_COPYIN: ! 2551: if ((data = msg->b_cont) != NULL) ! 2552: freemsg (data); ! 2553: ! 2554: /* ! 2555: * The STREAMS documentation is unclear as to whether ! 2556: * these blocks are split up or not, but it seems ! 2557: * unlikely. ! 2558: */ ! 2559: ! 2560: if ((data = MSGB_ALLOC (ioc->req.cq_size, BPRI_LO, ! 2561: KM_SLEEP)) == NULL) ! 2562: retval = ENOSR; ! 2563: else if (copyin (ioc->req.cq_addr, data->b_rptr, ! 2564: ioc->req.cq_size) != 0) { ! 2565: freemsg (data); ! 2566: data = NULL; ! 2567: retval = EFAULT; ! 2568: } else { ! 2569: ! 2570: data->b_wptr = data->b_rptr + ! 2571: ioc->req.cq_size; ! 2572: retval = 0; ! 2573: } ! 2574: ! 2575: msg->b_cont = data; ! 2576: break; ! 2577: ! 2578: case M_COPYOUT: ! 2579: retval = 0; ! 2580: ! 2581: while (ioc->req.cq_size > 0 && ! 2582: (data = msg->b_cont) != NULL) { ! 2583: size_t unit; ! 2584: ! 2585: /* ! 2586: * Copy a single M_DATA block at a time. After ! 2587: * copying, we free the block. ! 2588: */ ! 2589: ! 2590: unit = data->b_wptr - data->b_rptr; ! 2591: if (unit > ioc->req.cq_size) ! 2592: unit = ioc->req.cq_size; ! 2593: ! 2594: if (copyout (data->b_rptr, ioc->req.cq_addr, ! 2595: unit) != 0) { ! 2596: retval = EFAULT; ! 2597: break; ! 2598: } ! 2599: ! 2600: ioc->req.cq_size -= unit; ! 2601: ioc->req.cq_addr += unit; ! 2602: ! 2603: msg->b_cont = data->b_cont; ! 2604: freeb (data); ! 2605: } ! 2606: ! 2607: /* ! 2608: * Throw away uncopied extra data. ! 2609: */ ! 2610: ! 2611: if ((data = msg->b_cont) != NULL) ! 2612: freemsg (data); ! 2613: ! 2614: msg->b_cont = NULL; ! 2615: break; ! 2616: ! 2617: default: ! 2618: cmn_err (CE_WARN, "Invalid message type %d received during unlink processing", ! 2619: msg->b_datap->db_type); ! 2620: retval = ENXIO; ! 2621: goto done; ! 2622: } ! 2623: ! 2624: /* ! 2625: * In common code for M_COPYIN and M_COPYOUT, we turn around ! 2626: * the request message. If the request succeeded, we wrap ! 2627: * around to the top of the loop to serve the next request; ! 2628: * it there has been an error, we just put the message and ! 2629: * bail out. ! 2630: */ ! 2631: ! 2632: msg->b_datap->db_type = M_IOCDATA; ! 2633: ioc->resp.cp_rval = (caddr_t) retval; ! 2634: ! 2635: if (retval != 0) { ! 2636: ! 2637: putq (W (sheadp->sh_head), msg); ! 2638: break; ! 2639: } ! 2640: } ! 2641: ! 2642: done: ! 2643: freemsg (msg); ! 2644: ! 2645: return retval; ! 2646: } ! 2647: ! 2648: ! 2649: /* ! 2650: * This function contains code common to the ioctl () message processing for ! 2651: * stream link and unlink commands. These ioctl ()s send messages downstream ! 2652: * which are all of a single common form. ! 2653: */ ! 2654: ! 2655: #if __USE_PROTO__ ! 2656: __LOCAL__ int (LINK_MESSAGE) (shead_t * upper, int mode, shead_t * lower, ! 2657: int cmd, int muxid, cred_t * credp, ! 2658: int * retvalp) ! 2659: #else ! 2660: __LOCAL__ int ! 2661: LINK_MESSAGE __ARGS ((upper, mode, lower, cmd, muxid, credp, retvalp)) ! 2662: shead_t * upper; ! 2663: int mode; ! 2664: shead_t * lower; ! 2665: int cmd; ! 2666: int muxid; ! 2667: cred_t * credp; ! 2668: int * retvalp; ! 2669: #endif ! 2670: { ! 2671: mblk_t * msg; ! 2672: struct iocblk * ioc; ! 2673: struct linkblk * linkblk; ! 2674: int ackflag; ! 2675: queue_t * q; ! 2676: ! 2677: ASSERT_SLEEP_LOCKED (upper, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 2678: ASSERT_SLEEP_LOCKED (lower, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 2679: ASSERT (credp != NULL); ! 2680: ! 2681: /* ! 2682: * Set ourselves up for a STREAMS ioctl (). Note that since we keep ! 2683: * transparent ioctl () processing separate from normal I_STR code, we ! 2684: * don't have to allocate an initial message block that can be turned ! 2685: * into a "copyreq" or "copyresp" structure. ! 2686: */ ! 2687: ! 2688: ! 2689: if ((msg = MSGB_ALLOC (sizeof (* ioc), BPRI_LO, KM_SLEEP)) == NULL) ! 2690: return ENOSR; ! 2691: ! 2692: ioc = (struct iocblk *) msg->b_rptr; ! 2693: msg->b_wptr = (unsigned char *) (ioc + 1); ! 2694: ! 2695: msg->b_datap->db_type = M_IOCTL; ! 2696: ! 2697: ioc->ioc_cmd = cmd; ! 2698: ioc->ioc_cr = credp; ! 2699: ioc->ioc_id = ++ upper->sh_ioc_seq; ! 2700: ioc->ioc_count = sizeof (struct linkblk); ! 2701: ioc->ioc_rval = ioc->ioc_error = 0; ! 2702: ! 2703: ! 2704: /* ! 2705: * Now we allocate and fill in the data part of the I_...LINK message. ! 2706: */ ! 2707: ! 2708: if ((msg->b_cont = MSGB_ALLOC (sizeof (struct linkblk), BPRI_LO, ! 2709: KM_SLEEP)) == NULL) { ! 2710: freeb (msg); ! 2711: return ENOSR; ! 2712: } ! 2713: ! 2714: linkblk = (struct linkblk *) msg->b_cont->b_rptr; ! 2715: msg->b_cont->b_wptr = (unsigned char *) (linkblk + 1); ! 2716: ! 2717: ! 2718: /* ! 2719: * Find the bottom-most write queue on the upper stream. To make this ! 2720: * walk of the queue safe with respect to I_PUSH and I_POP, we take ! 2721: * out a read lock on the stream head. See the PUSH_MODULE () and ! 2722: * POP_MODULE () routines for more details on this. ! 2723: * ! 2724: * We don't use QUEUE_NEXT () because the intermediate modules are of ! 2725: * no interest to us; we just want the driver at the bottom. ! 2726: */ ! 2727: ! 2728: { ! 2729: queue_t * next; ! 2730: ! 2731: (void) SHEAD_LOCK (upper); ! 2732: ! 2733: next = W (upper->sh_head); ! 2734: ! 2735: do { ! 2736: q = next; ! 2737: ! 2738: (void) QFREEZE_TRACE (q, "LINK_MESSAGE"); ! 2739: ! 2740: next = q->q_next; ! 2741: ! 2742: QUNFREEZE_TRACE (q, plbase); ! 2743: } while (next != NULL); ! 2744: ! 2745: SHEAD_UNLOCK (upper, plbase); ! 2746: } ! 2747: ! 2748: linkblk->l_qtop = q; ! 2749: linkblk->l_qbot = lower->sh_head; ! 2750: linkblk->l_index = muxid; ! 2751: ! 2752: ! 2753: /* ! 2754: * Now we send the ioctl () and wait for the acknowledgement. Since ! 2755: * there is no mechanism for managing this timeout, we will use the ! 2756: * close timeout (which is appropriate given that this operation will ! 2757: * often be performed as the result of a close ()). ! 2758: */ ! 2759: ! 2760: if ((msg = IOCTL_SEND (upper, mode, msg, retvalp, ! 2761: upper->sh_cltime)) == NULL) ! 2762: return 0; /* counts as a negative ack */ ! 2763: ! 2764: /* ! 2765: * Now we see what kind of message the driver has send to us. ! 2766: */ ! 2767: ! 2768: ioc = (struct iocblk *) msg->b_rptr; ! 2769: ! 2770: if (retvalp != NULL) ! 2771: * retvalp = ioc->ioc_error; ! 2772: ! 2773: switch (msg->b_datap->db_type) { ! 2774: ! 2775: case M_IOCNAK: ! 2776: ackflag = 0; ! 2777: break; ! 2778: ! 2779: case M_IOCACK: ! 2780: /* ! 2781: * We do not copy the "ioc_rval" member out because it is not ! 2782: * documented as forming the return value from such a link- ! 2783: * style ioctl () request. ! 2784: */ ! 2785: ! 2786: /* ! 2787: * Since "arg" for an I_UNLINK or I_PUNLINK is not a pointer, ! 2788: * it makes no sense for a driver to attempt to return data ! 2789: * for the user. Since the canonical multiplexing driver code ! 2790: * clears ioc_count and simply turns around the message, it ! 2791: * is not a problem for there to be M_DATA messages following ! 2792: * the M_IOCACK, but it is a problem if "ioc_count" is greater ! 2793: * than 0. ! 2794: */ ! 2795: ! 2796: ackflag = 1; ! 2797: ! 2798: if (ioc->ioc_count > 0) ! 2799: cmn_err (CE_WARN, "Driver %s returned data with link/unlink ioctl ()", ! 2800: q->q_qinfo->qi_minfo->mi_idname); ! 2801: ! 2802: break; ! 2803: ! 2804: default: ! 2805: cmn_err (CE_WARN, "Invalid message type %d received during link/unlink processing", ! 2806: msg->b_datap->db_type); ! 2807: * retvalp = ENXIO; ! 2808: ! 2809: ackflag = 0; /* treat as a negative ack */ ! 2810: break; ! 2811: } ! 2812: ! 2813: freemsg (msg); ! 2814: ! 2815: return ackflag; ! 2816: } ! 2817: ! 2818: ! 2819: /* ! 2820: * Helper function for the link/unlink process to restore a stream to the ! 2821: * unlinked state. ! 2822: */ ! 2823: ! 2824: #if __USE_PROTO__ ! 2825: __LOCAL__ int (SHEAD_INIT_UNLINKED) (shead_t * sheadp) ! 2826: #else ! 2827: __LOCAL__ int ! 2828: SHEAD_INIT_UNLINKED __ARGS ((sheadp)) ! 2829: shead_t * sheadp; ! 2830: #endif ! 2831: { ! 2832: pl_t prev_pl; ! 2833: int final_close; ! 2834: ! 2835: ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 2836: ! 2837: /* ! 2838: * The driver is no longer using this stream; restore it to normal ! 2839: * operation. Note that we have to reset "q_ptr" back to point at the ! 2840: * stream head! ! 2841: */ ! 2842: ! 2843: prev_pl = SHEAD_LOCK (sheadp); ! 2844: ! 2845: sheadp->sh_linked = NULL; ! 2846: sheadp->sh_flags &= ~ SH_PLINK; ! 2847: ! 2848: final_close = -- sheadp->sh_open_count == 0; ! 2849: ! 2850: SHEAD_UNLOCK (sheadp, prev_pl); ! 2851: ! 2852: ! 2853: prev_pl = QFREEZE_TRACE (sheadp->sh_head, "SHEAD_INIT_UNLINKED"); ! 2854: ! 2855: sheadp->sh_head->q_ptr = sheadp; ! 2856: W (sheadp->sh_head)->q_ptr = sheadp; ! 2857: ! 2858: QUEUE_INIT (sheadp->sh_head, sheadp->sh_tab, QI_NORMAL); ! 2859: ! 2860: QUNFREEZE_TRACE (sheadp->sh_head, prev_pl); ! 2861: ! 2862: return final_close; ! 2863: } ! 2864: ! 2865: ! 2866: /* ! 2867: * This function takes care of unlinking a lower stream from an upper stream. ! 2868: * ! 2869: * The caller should have both the upper and lower stream heads locked for ! 2870: * open/close processing. ! 2871: */ ! 2872: ! 2873: #if __USE_PROTO__ ! 2874: __LOCAL__ int (LOCKED_UNLINK) (shead_t * upper, int mode, shead_t * lower, ! 2875: int cmd, cred_t * credp, int * retvalp) ! 2876: #else ! 2877: __LOCAL__ int ! 2878: LOCKED_UNLINK __ARGS ((upper, mode, lower, cmd, credp, retvalp)) ! 2879: shead_t * upper; ! 2880: int mode; ! 2881: shead_t * lower; ! 2882: int cmd; ! 2883: cred_t * credp; ! 2884: int * retvalp; ! 2885: #endif ! 2886: { ! 2887: ASSERT_SLEEP_LOCKED (upper, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 2888: ASSERT_SLEEP_LOCKED (lower, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 2889: ! 2890: /* ! 2891: * Check that the right kind of unlink command is being issued. ! 2892: */ ! 2893: ! 2894: if (lower->sh_linked != upper || ! 2895: ((lower->sh_flags & SH_PLINK) != 0) == (cmd == I_PUNLINK)) ! 2896: return EINVAL; ! 2897: ! 2898: /* ! 2899: * Send the message downstream and get the return result. ! 2900: */ ! 2901: ! 2902: if (LINK_MESSAGE (upper, mode, lower, cmd, lower->sh_muxid, credp, ! 2903: retvalp)) { ! 2904: /* ! 2905: * The unlink was properly acknowledged. Note that this may ! 2906: * cause the lower stream to close. ! 2907: */ ! 2908: ! 2909: if (SHEAD_INIT_UNLINKED (lower) != 0) ! 2910: SHEAD_DO_CLOSE (lower, mode, credp); ! 2911: ! 2912: return 1; ! 2913: } ! 2914: ! 2915: return 0; ! 2916: } ! 2917: ! 2918: ! 2919: /* ! 2920: * This function wraps up part of the required client functionality for ! 2921: * callers of SHEAD_UNLINK () by dealing with locking the lower stream head ! 2922: * and making appropriate calls to see if it needs closing. ! 2923: */ ! 2924: ! 2925: #if __USE_PROTO__ ! 2926: __LOCAL__ int (SHEAD_UNLINK) (shead_t * upper, shead_t * lower, int cmd, ! 2927: int mode, cred_t * credp, int * retvalp) ! 2928: #else ! 2929: __LOCAL__ int ! 2930: SHEAD_UNLINK __ARGS ((upper, lower, cmd, mode, credp, retvalp)) ! 2931: shead_t * upper; ! 2932: shead_t * lower; ! 2933: int cmd; ! 2934: int mode; ! 2935: cred_t * credp; ! 2936: int * retvalp; ! 2937: #endif ! 2938: { ! 2939: int success; ! 2940: ! 2941: /* ! 2942: * In order to unlink this lower stream we first have to lock it. This ! 2943: * is necessary not only to ensure that we don't trip up other ! 2944: * operations affecting this stream (since there may be open file ! 2945: * descriptors referring to it, and/or it may be a stream pipe) but ! 2946: * since stream deallocations are checked for in the unlock code this ! 2947: * is necessary to ensure that an unlink of an otherwise unreferenced ! 2948: * stream does the right thing. ! 2949: */ ! 2950: ! 2951: if ((* retvalp = SHEAD_SLEEP_LOCK (lower, ! 2952: SH_OPENCLOSE | SH_IOCTL_LOCK, 0, ! 2953: DONT_SIGNAL)) != 0) { ! 2954: ! 2955: cmn_err (CE_WARN, "Unable to lock stream in SHEAD_UNLINK (), error %d", ! 2956: * retvalp); ! 2957: return 1; ! 2958: } ! 2959: ! 2960: ! 2961: /* ! 2962: * OK, we unlink this lower stream, and do all the stuff we ! 2963: * need to do to ensure that the lower stream gets closed if ! 2964: * its time has come. ! 2965: */ ! 2966: ! 2967: success = LOCKED_UNLINK (upper, mode, lower, cmd, credp, retvalp); ! 2968: ! 2969: SHEAD_SLEEP_UNLOCK (lower, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 2970: ! 2971: return success; ! 2972: } ! 2973: ! 2974: ! 2975: /* ! 2976: * Loop-detection algorithm for use in SHEAD_LINK (). ! 2977: * ! 2978: * The STREAMS documentation is very vague about what constitutes a cycle in ! 2979: * the link graph, probably deliberately. ! 2980: * ! 2981: * For our purposes we consider a cycle to be caused by any path of links ! 2982: * which lead upwards (to user level) from the *device* indicated by "upper" ! 2983: * to the *device* indicated by "lower". ! 2984: * ! 2985: * Frankly, given the nature of multiplexing drivers in terms of routing ! 2986: * information, I really don't see much advantage in this; it is perfectly ! 2987: * easy for messages cycles to form other ways, and given the typical nature ! 2988: * of multiplexor services interfaces a cycle in the hierarchy need not cause ! 2989: * a loop. Still, that's the way it's specified. ! 2990: * ! 2991: * THIS IS A RECURSIVE ALGORITHM FOR DEPTH-FIRST SEARCH. This fact does not ! 2992: * really worry me in the slightest, because the depth of the recursion here ! 2993: * is no worse than the possible recursive depth of the multiplexor put () ! 2994: * calls themselves. ! 2995: */ ! 2996: ! 2997: #if __USE_PROTO__ ! 2998: __LOCAL__ int (DETECT_LOOP) (shead_t * upper, shead_t * lower) ! 2999: #else ! 3000: __LOCAL__ int ! 3001: DETECT_LOOP __ARGS ((upper, lower)) ! 3002: shead_t * upper; ! 3003: shead_t * lower; ! 3004: #endif ! 3005: { ! 3006: shead_t * scan; ! 3007: ! 3008: /* ! 3009: * We base our comparisons on the "sh_tab" member of the stream head ! 3010: * structure, since that is equivalent to the major part of the ! 3011: * (internal) device number. ! 3012: */ ! 3013: ! 3014: if (upper->sh_tab == lower->sh_tab) ! 3015: return 1; ! 3016: ! 3017: /* ! 3018: * Now recursively work upward through the multiplexing configuration ! 3019: * calling DETECT_LOOP () for all the linked streams with the "sh_tab" ! 3020: * entry of the stream which "upper" is linked to (if "upper" is in ! 3021: * fact linked below another multiplexor). ! 3022: * ! 3023: * Since only device streams can be multiplexors, we only scan the ! 3024: * device stream list. ! 3025: */ ! 3026: ! 3027: if ((upper = upper->sh_linked) == NULL) ! 3028: return 0; ! 3029: ! 3030: for (scan = str_mem->sm_streams [DEV_SLIST] ; scan != NULL ; ! 3031: scan = scan->sh_next) { ! 3032: ! 3033: if (scan->sh_tab == upper->sh_tab && ! 3034: DETECT_LOOP (scan, lower)) ! 3035: return 1; ! 3036: } ! 3037: ! 3038: return 0; ! 3039: } ! 3040: ! 3041: ! 3042: /* ! 3043: * This function deals with linking one stream below another. There are ! 3044: * numerous conditions which might prevent this from happening, including a ! 3045: * refusal from the multiplexing driver. ! 3046: * ! 3047: * The upper stream must be locked for open/close operations. The lower stream ! 3048: * will also be locked by this routine. ! 3049: */ ! 3050: ! 3051: #if __USE_PROTO__ ! 3052: int (SHEAD_LINK) (shead_t * upper, int mode, shead_t * lower, int cmd, ! 3053: cred_t * credp) ! 3054: #else ! 3055: int ! 3056: SHEAD_LINK __ARGS ((upper, mode, lower, cmd, credp)) ! 3057: shead_t * upper; ! 3058: int mode; ! 3059: shead_t * lower; ! 3060: int cmd; ! 3061: cred_t * credp; ! 3062: #endif ! 3063: { ! 3064: int retval; ! 3065: muxid_t muxid; ! 3066: ! 3067: ASSERT (lower != NULL); ! 3068: ! 3069: ASSERT_SLEEP_LOCKED (upper, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 3070: ! 3071: if (SHEAD_IS_PIPE (upper) || ! 3072: upper->sh_tab->st_muxrinit == NULL || ! 3073: upper->sh_tab->st_muxwinit == NULL) ! 3074: return EINVAL; ! 3075: ! 3076: /* ! 3077: * Perform some of the non-recursive setup (mainly locking) for the ! 3078: * cycle-detection algorithm. We use the read/write lock on the stream ! 3079: * head since the detection algorithm walks over the global stream ! 3080: * list many times. Note that this single-threads checking operations, ! 3081: * which we would also have to do if were were pushing marker bits ! 3082: * around in a non-recursive implementation. ! 3083: */ ! 3084: ! 3085: (void) RW_WRLOCK (str_mem->sm_head_lock, plstr); ! 3086: ! 3087: retval = DETECT_LOOP (upper, lower); ! 3088: ! 3089: RW_UNLOCK (str_mem->sm_head_lock, plbase); ! 3090: ! 3091: if (retval != 0) ! 3092: return EINVAL; ! 3093: ! 3094: /* ! 3095: * Generate a suitable multiplexor ID for the link. We use the device ! 3096: * number of the lower stream as a suitable seed point. ! 3097: */ ! 3098: ! 3099: for (muxid = (muxid_t) lower->sh_dev ; ! 3100: SHEAD_FIND_MUXID (upper, cmd, muxid) != NULL ; muxid ++) ! 3101: ; /* DO NOTHING */ ! 3102: ! 3103: /* ! 3104: * We set up the lower now, before we send the I_LINK, so that by the ! 3105: * time the driver sees the I_LINK the stream is ready for use. We ! 3106: * NULL out the "q_ptr" member of the lower queue so that messages ! 3107: * arriving early can be correctly handled. ! 3108: * ! 3109: * We take a sleep lock on the lower stream. If we can't lock it, ! 3110: * return EINVAL since whatever error caused the failure isn't really ! 3111: * relevant to the stream the caller is dealing with. ! 3112: */ ! 3113: ! 3114: if ((retval = SHEAD_SLEEP_LOCK (lower, SH_OPENCLOSE | SH_IOCTL_LOCK, ! 3115: 0, DONT_SIGNAL)) != 0) ! 3116: return EINVAL; ! 3117: ! 3118: /* ! 3119: * Note that the "q_ptr" field of the queue gets zeroed to avoid ! 3120: * communicating our state to the driver. In addition, we have to ! 3121: * count the link as an extra open now. ! 3122: * ! 3123: * Paranoia time; we check for errors, hangups and whether the lower ! 3124: * stream is linked at this late stage so the cutover is atomic. This ! 3125: * requires some cooperation from the stream head read side service ! 3126: * routine; look to see that it tests for "sh_linked" in the service ! 3127: * routine somewhere... ! 3128: */ ! 3129: ! 3130: (void) SHEAD_LOCK (lower); ! 3131: ! 3132: if (SHEAD_HANGUP (lower) || _shead_error (lower, FREAD | FWRITE)) { ! 3133: ! 3134: SHEAD_UNLOCK (lower, plbase); ! 3135: SHEAD_SLEEP_UNLOCK (lower, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 3136: return EINVAL; ! 3137: } ! 3138: ! 3139: lower->sh_open_count ++; /* duplicate reference */ ! 3140: ! 3141: lower->sh_linked = upper; ! 3142: lower->sh_muxid = muxid; ! 3143: ! 3144: if (cmd == I_PLINK) ! 3145: lower->sh_flags |= SH_PLINK; ! 3146: ! 3147: SHEAD_UNLOCK (lower, plbase); ! 3148: ! 3149: ! 3150: (void) QFREEZE_TRACE (lower->sh_head, "LINK_STREAMS"); ! 3151: ! 3152: lower->sh_head->q_ptr = NULL; ! 3153: W (lower->sh_head)->q_ptr = NULL; ! 3154: ! 3155: QUEUE_INIT (lower->sh_head, lower->sh_tab, QI_MUX); ! 3156: ! 3157: QUNFREEZE_TRACE (lower->sh_head, plbase); ! 3158: ! 3159: ! 3160: /* ! 3161: * Send the message downstream and get the return result. ! 3162: */ ! 3163: ! 3164: if (LINK_MESSAGE (upper, mode, lower, cmd, muxid, credp, ! 3165: & retval) == 0) { ! 3166: int final; ! 3167: ! 3168: /* ! 3169: * The driver failed the link; restore the lower stream. This ! 3170: * won't cause the stream to close (because of our open ! 3171: * reference) but we take care to ensure that the counts are ! 3172: * properly maintained. ! 3173: */ ! 3174: ! 3175: final = SHEAD_INIT_UNLINKED (lower); ! 3176: ! 3177: if (final != 0) ! 3178: cmn_err (CE_WARN, "Final close in SHEAD_LINK () ????"); ! 3179: } ! 3180: ! 3181: ! 3182: /* ! 3183: * Unlock the lower stream for proper symmetry. ! 3184: */ ! 3185: ! 3186: SHEAD_SLEEP_UNLOCK (lower, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 3187: return retval; ! 3188: } ! 3189: ! 3190: ! 3191: /* ! 3192: * This function deals with a special case in SHEAD_DO_CLOSE () below where ! 3193: * the last close of a stream pipe end causes the other end to be detached ! 3194: * from all the filesystem entries it has been mounted over. ! 3195: */ ! 3196: ! 3197: #if __USE_PROTO__ ! 3198: __LOCAL__ void (SHEAD_PIPE_DETACH) (shead_t * __NOTUSED (other)) ! 3199: #else ! 3200: __LOCAL__ void ! 3201: SHEAD_PIPE_DETACH __ARGS ((other)) ! 3202: shead_t * other; ! 3203: #endif ! 3204: { ! 3205: /* ! 3206: * Until we know how attachments are going to be performed and what ! 3207: * kind of structure exists, we cannot implement this function. ! 3208: */ ! 3209: ! 3210: cmn_err (CE_PANIC, "UNIMPLEMENTED : SHEAD_PIPE_DETACH ()"); ! 3211: } ! 3212: ! 3213: ! 3214: /* ! 3215: * This module factors out some code from SHEAD_DO_CLOSE (). The final ! 3216: * close processing for a stream head is complicated a little because when a ! 3217: * stream pipe end is closed that side of the pipe is not actually closed ! 3218: * until the other end also closes. ! 3219: */ ! 3220: ! 3221: #if __USE_PROTO__ ! 3222: __LOCAL__ void (SHEAD_FINAL_CLOSE) (shead_t * sheadp, int mode, ! 3223: cred_t * credp) ! 3224: #else ! 3225: __LOCAL__ void ! 3226: SHEAD_FINAL_CLOSE __ARGS ((sheadp, mode, credp)) ! 3227: shead_t * sheadp; ! 3228: int mode; ! 3229: cred_t * credp; ! 3230: #endif ! 3231: { ! 3232: shead_t * scan; ! 3233: queue_t * q; ! 3234: int retval; ! 3235: ! 3236: /* ! 3237: * Final close of a stream; the close steps are to be performed in ! 3238: * this order, as given in the DDI/DDK entry for close(D2DK). ! 3239: * Non-persistent multiplexor links are unlinked. ! 3240: * For each module and driver from the head to the driver: ! 3241: * Wait for the write queue to drain. ! 3242: * Call close () routine. ! 3243: * Remove module/driver from stream. ! 3244: * Free remaining messages. ! 3245: * Deallocate queue pair. ! 3246: * ! 3247: * Here we can behave as if we have an ioctl () lock on the stream ! 3248: * because during final close no other process can legitimately hold ! 3249: * another lock on the stream head (no other legal references to the ! 3250: * stream exist). ! 3251: */ ! 3252: ! 3253: while ((scan = SHEAD_FIND_MUXID (sheadp, I_UNLINK, -1)) != NULL) { ! 3254: ! 3255: if (SHEAD_UNLINK (sheadp, scan, I_UNLINK, mode, credp, ! 3256: & retval) == 0) { ! 3257: /* ! 3258: * There is no good reason for a driver to fail an ! 3259: * I_UNLINK request. ! 3260: */ ! 3261: ! 3262: cmn_err (CE_WARN, "Driver failed unlink () during final close (%d)", ! 3263: retval); ! 3264: scan->sh_linked = NULL; ! 3265: } ! 3266: } ! 3267: ! 3268: ! 3269: /* ! 3270: * Before draining the write side modules, drain the stream head. ! 3271: */ ! 3272: ! 3273: DRAIN_QUEUE (sheadp, W (sheadp->sh_head)); ! 3274: ! 3275: ! 3276: /* ! 3277: * Now pop all the modules from the stream. ! 3278: */ ! 3279: ! 3280: while ((q = TOP_MODULE (sheadp)) != NULL) { ! 3281: ! 3282: DRAIN_QUEUE (sheadp, W (q)); ! 3283: ! 3284: (void) POP_MODULE (sheadp, q, mode, credp); ! 3285: } ! 3286: ! 3287: ! 3288: /* ! 3289: * Now close the driver, unless this is a pipe. Once this has been ! 3290: * done there is no reason for any context to reference this object ! 3291: * except to unlock it. ! 3292: */ ! 3293: ! 3294: if (! SHEAD_IS_PIPE (sheadp)) { ! 3295: q = TOP_QUEUE (sheadp); ! 3296: ! 3297: DRAIN_QUEUE (sheadp, q); ! 3298: ! 3299: q = R (q); ! 3300: ! 3301: retval = (* q->q_qinfo->qi_qclose) (q, mode, credp); ! 3302: ! 3303: if (retval != 0) ! 3304: cmn_err (CE_WARN, "Driver close returned %d", retval); ! 3305: ! 3306: if ((q->q_flag & QPROCSOFF) == 0) { ! 3307: ! 3308: cmn_err (CE_WARN, "Driver %s did not call qprocsoff ()", ! 3309: q->q_qinfo->qi_minfo->mi_idname); ! 3310: qprocsoff (q); ! 3311: } ! 3312: } ! 3313: } ! 3314: ! 3315: ! 3316: /* ! 3317: * This function does most of the close processing for a stream head. It is ! 3318: * used by regular stream close, and by stream open code if certain ! 3319: * irregularities are detected. ! 3320: * ! 3321: * The caller must have the stream head locked for close operations. If the ! 3322: * stream head being operated on is a pipe, that means both ends must be ! 3323: * locked (so that the caller can sequence the lock order on the basis of the ! 3324: * master/slave bits). ! 3325: */ ! 3326: ! 3327: #if __USE_PROTO__ ! 3328: __LOCAL__ int (SHEAD_DO_CLOSE) (shead_t * sheadp, int mode, cred_t * credp) ! 3329: #else ! 3330: __LOCAL__ int ! 3331: SHEAD_DO_CLOSE __ARGS ((sheadp, mode, credp)) ! 3332: shead_t * sheadp; ! 3333: int mode; ! 3334: cred_t * credp; ! 3335: #endif ! 3336: { ! 3337: ASSERT (credp != NULL); ! 3338: ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 3339: ! 3340: /* ! 3341: * If other processes have references to this stream head, then we can ! 3342: * just return doing no more work. Note that we keep the notion of ! 3343: * number of open references, number of filesystem attachments, and ! 3344: * multiplexor links completely separate, but any one qualifies as ! 3345: * a reason for keeping the stream around. ! 3346: * ! 3347: * Therefore, it follows that any code which manipulates any of these ! 3348: * quantities such that the next expression might become false needs ! 3349: * to call this function to ensure that the stream memory will be ! 3350: * properly reclaimed. ! 3351: */ ! 3352: ! 3353: ASSERT (sheadp->sh_open_count == 0); ! 3354: ! 3355: if (SHEAD_IS_PIPE (sheadp)) { ! 3356: shead_t * other = SHEAD_OTHER (sheadp); ! 3357: ! 3358: /* ! 3359: * If this is a pipe, there are some extra things we should ! 3360: * worry about. First, the first end of a stream pipe to close ! 3361: * should send an M_HANGUP message to the other end rather ! 3362: * than actually closing. The other end then gets to destroy ! 3363: * both sides of the pipe when it finally closes. ! 3364: * ! 3365: * The second exception is that when an unattached end of a ! 3366: * streams pipe is closed, the other end is automatically ! 3367: * detached. ! 3368: * ! 3369: * Note that if the other end of the pipe is linked below a ! 3370: * multiplexor, we do not attempt to automatically unlink it. ! 3371: * This might seem entirely reasonable, but we cannot attempt ! 3372: * this without introducing a possibility of deadlock. ! 3373: */ ! 3374: ! 3375: if (other->sh_attach_count > 0) ! 3376: SHEAD_PIPE_DETACH (other); ! 3377: ! 3378: if (other->sh_open_count > 0) { ! 3379: /* ! 3380: * The last close/detach/unlink of the other end will ! 3381: * clean everything up. ! 3382: */ ! 3383: ! 3384: putctl (W (other->sh_head), M_HANGUP); ! 3385: return 0; ! 3386: } ! 3387: ! 3388: /* ! 3389: * Now we clean up the "other" end. ! 3390: */ ! 3391: ! 3392: SHEAD_FINAL_CLOSE (other, mode, credp); ! 3393: } ! 3394: ! 3395: SHEAD_FINAL_CLOSE (sheadp, mode, credp); ! 3396: ! 3397: /* ! 3398: * We leave the last part of the cleanup (dallocating the queue pair ! 3399: * and any remaining messages) to the unlock call which the caller ! 3400: * will perform. ! 3401: */ ! 3402: ! 3403: return 0; ! 3404: } ! 3405: ! 3406: ! 3407: /* ! 3408: * This function builds and send an M_FLUSH message down the stream. ! 3409: */ ! 3410: ! 3411: #if __USE_PROTO__ ! 3412: __LOCAL__ int (SHEAD_FLUSH) (shead_t * sheadp, int flag, uchar_t band) ! 3413: #else ! 3414: __LOCAL__ int ! 3415: SHEAD_FLUSH __ARGS ((sheadp, flag, band)) ! 3416: shead_t * sheadp; ! 3417: int flag; ! 3418: uchar_t band; ! 3419: #endif ! 3420: { ! 3421: mblk_t * msg; ! 3422: ! 3423: if ((flag & FLUSHRW) == 0 || (flag & ~ FLUSHRW) != 0) ! 3424: return EINVAL; ! 3425: else if ((msg = MSGB_ALLOC (2, BPRI_LO, KM_SLEEP)) == NULL) ! 3426: return ENOSR; ! 3427: else { ! 3428: /* ! 3429: * Send the message downstream... ! 3430: */ ! 3431: ! 3432: if (band > 0) ! 3433: flag |= FLUSHBAND; ! 3434: ! 3435: msg->b_datap->db_type = M_FLUSH; ! 3436: * msg->b_wptr ++ = (unsigned char) flag; ! 3437: ! 3438: if (band > 0) ! 3439: * msg->b_wptr ++ = band; ! 3440: ! 3441: put (W (sheadp->sh_head), msg); ! 3442: } ! 3443: ! 3444: return 0; ! 3445: } ! 3446: ! 3447: ! 3448: /* ! 3449: * This function locates a module's streamtab entry given the name. Only the ! 3450: * first FMNAMESZ characters are considered significant. ! 3451: */ ! 3452: ! 3453: #if __USE_PROTO__ ! 3454: modsw_t * (FIND_MODULE) (__CONST__ char * modname) ! 3455: #else ! 3456: modsw_t * ! 3457: FIND_MODULE __ARGS ((modname)) ! 3458: __CONST__ char * modname; ! 3459: #endif ! 3460: { ! 3461: modsw_t * scan; ! 3462: modsw_t * end; ! 3463: ! 3464: for (scan = modsw, end = scan + nmodsw ; scan != end ; scan ++) { ! 3465: __CONST__ char * name; ! 3466: ! 3467: name = scan->mod_stream->st_rdinit->qi_minfo->mi_idname; ! 3468: ! 3469: if (name != NULL && strncmp (modname, name, FMNAMESZ) == 0) ! 3470: return scan; ! 3471: } ! 3472: ! 3473: return NULL; ! 3474: } ! 3475: ! 3476: ! 3477: /* ! 3478: * This function holds code to process an I_STR ioctl (). ! 3479: */ ! 3480: ! 3481: #if __USE_PROTO__ ! 3482: __LOCAL__ int (ISTR_IOCTL) (shead_t * sheadp, int mode, ! 3483: struct strioctl * strioc, cred_t * credp, ! 3484: int * rvalp) ! 3485: #else ! 3486: __LOCAL__ int ! 3487: ISTR_IOCTL __ARGS ((sheadp, mode, strioc, credp, rvalp)) ! 3488: shead_t * sheadp; ! 3489: int mode; ! 3490: struct strioctl ! 3491: * strioc; ! 3492: cred_t * credp; ! 3493: int * rvalp; ! 3494: #endif ! 3495: { ! 3496: __clock_t ticks; ! 3497: mblk_t * msg; ! 3498: mblk_t * data; ! 3499: struct iocblk * ioc; ! 3500: int retval; ! 3501: ! 3502: ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK); ! 3503: ! 3504: /* ! 3505: * Set up timeout; "ic_timeout" == -1 means infinite ! 3506: * timeout, while "ic_timeout" == 0 means default ! 3507: * (which is infinite). ! 3508: */ ! 3509: ! 3510: if (strioc->ic_timeout != -1 && strioc->ic_timeout != 0) { ! 3511: /* ! 3512: * We take care to deal with overflow here. ! 3513: */ ! 3514: ! 3515: if ((ticks = strioc->ic_timeout) > (__clock_t) -1 / 1000000L) ! 3516: ticks = (__clock_t) -1; ! 3517: ! 3518: ticks = drv_usectohz (ticks * 1000000L); ! 3519: } else ! 3520: ticks = 0; ! 3521: ! 3522: if ((msg = MSGB_ALLOC (sizeof (* ioc), BPRI_LO, KM_SLEEP)) == NULL) ! 3523: return ENOSR; ! 3524: ! 3525: ioc = (struct iocblk *) msg->b_rptr; ! 3526: msg->b_wptr = (unsigned char *) (ioc + 1); ! 3527: ! 3528: msg->b_datap->db_type = M_IOCTL; ! 3529: ! 3530: ioc->ioc_cmd = strioc->ic_cmd; ! 3531: ioc->ioc_cr = credp; ! 3532: ioc->ioc_id = ++ sheadp->sh_ioc_seq; ! 3533: ioc->ioc_count = strioc->ic_len; ! 3534: ioc->ioc_rval = ioc->ioc_error = 0; ! 3535: ! 3536: ! 3537: /* ! 3538: * If there is data to be sent downstream, we allocate a buffer to ! 3539: * hold it and copy the data into that buffer. ! 3540: */ ! 3541: ! 3542: if (ioc->ioc_count > 0) { ! 3543: ! 3544: if ((data = MSGB_ALLOC (strioc->ic_len, BPRI_LO, ! 3545: KM_SLEEP)) == NULL) { ! 3546: ! 3547: retval = ENOSR; ! 3548: goto done; ! 3549: } ! 3550: ! 3551: msg->b_cont = data; ! 3552: data->b_wptr += strioc->ic_len; ! 3553: ! 3554: if (copyin (strioc->ic_dp, data->b_rptr, ! 3555: strioc->ic_len) != 0) { ! 3556: ! 3557: retval = EFAULT; ! 3558: goto done; ! 3559: } ! 3560: } ! 3561: ! 3562: /* ! 3563: * Now we send the ioctl () and wait for the acknowledgement. ! 3564: */ ! 3565: ! 3566: if ((msg = IOCTL_SEND (sheadp, mode, msg, & retval, ticks)) == NULL) ! 3567: return retval; ! 3568: ! 3569: ! 3570: /* ! 3571: * What do we do with the results? We copy at most "ioc_count" bytes ! 3572: * of data back into the user's address space if this is M_IOCACK. ! 3573: */ ! 3574: ! 3575: ioc = (struct iocblk *) msg->b_rptr; ! 3576: ! 3577: switch (msg->b_datap->db_type) { ! 3578: ! 3579: case M_IOCNAK: ! 3580: retval = ioc->ioc_error; ! 3581: break; ! 3582: ! 3583: case M_IOCACK: ! 3584: * rvalp = ioc->ioc_rval; ! 3585: retval = ioc->ioc_error; ! 3586: ! 3587: data = msg->b_cont; ! 3588: ! 3589: while (ioc->ioc_count > 0) { ! 3590: size_t len; ! 3591: ! 3592: if (data == NULL) { ! 3593: ! 3594: cmn_err (CE_WARN, "ISTR_IOCTL : Insufficient M_DATA blocks for ioc_count"); ! 3595: break; ! 3596: } ! 3597: ! 3598: len = data->b_wptr - data->b_rptr; ! 3599: ! 3600: if (len > ioc->ioc_count) ! 3601: len = ioc->ioc_count; ! 3602: ! 3603: if (len > 0 && ! 3604: copyout (data->b_rptr, strioc->ic_dp, ! 3605: len) != 0) { ! 3606: ! 3607: retval = EFAULT; ! 3608: goto done; ! 3609: } ! 3610: ! 3611: ioc->ioc_count -= len; ! 3612: data = data->b_cont; ! 3613: strioc->ic_dp += len; ! 3614: } ! 3615: break; ! 3616: ! 3617: default: ! 3618: cmn_err (CE_WARN, "Invalid message type %d received during unlink processing", ! 3619: msg->b_datap->db_type); ! 3620: retval = ENXIO; ! 3621: break; ! 3622: } ! 3623: ! 3624: done: ! 3625: freemsg (msg); ! 3626: ! 3627: return retval; ! 3628: } ! 3629: ! 3630: ! 3631: /* ! 3632: * Here are the details of the implementation of sigpoll_t. ! 3633: */ ! 3634: ! 3635: struct sigpoll { ! 3636: sigpoll_t * sp_next; /* single-threaded */ ! 3637: _VOID * sp_proc; /* from proc_ref () */ ! 3638: short sp_events; /* events to signal per <stropts.h> */ ! 3639: }; ! 3640: ! 3641: ! 3642: /* ! 3643: * This function is used when an M_SIG or M_PCSIG message is processed at the ! 3644: * stream head. ! 3645: */ ! 3646: ! 3647: #if __USE_PROTO__ ! 3648: void (SHEAD_SIGNAL) (shead_t * sheadp, uchar_t signal) ! 3649: #else ! 3650: void ! 3651: SHEAD_SIGNAL __ARGS ((sheadp, signal)) ! 3652: shead_t * sheadp; ! 3653: uchar_t signal; ! 3654: #endif ! 3655: { ! 3656: pl_t prev_pl; ! 3657: ! 3658: prev_pl = SHEAD_LOCK (sheadp); ! 3659: ! 3660: if (signal == SIGPOLL) { ! 3661: sigpoll_t * sigs; ! 3662: ! 3663: /* ! 3664: * SIGPOLL is only sent to those processes that have ! 3665: * registered to receive it with I_SETSIG. ! 3666: */ ! 3667: ! 3668: ! 3669: for (sigs = sheadp->sh_sigs ; sigs != NULL ; ! 3670: sigs = sigs->sp_next) { ! 3671: ! 3672: if ((sigs->sp_events & S_MSG) != 0) ! 3673: proc_signal (sigs->sp_proc, signal); ! 3674: } ! 3675: } else { ! 3676: /* ! 3677: * Send a signal to the controlling process group for this ! 3678: * stream; if this stream is not a controlling tty, then no ! 3679: * signal is sent. ! 3680: */ ! 3681: ! 3682: if (sheadp->sh_pgrp != 0) ! 3683: proc_kill_group (sheadp->sh_pgrp, signal); ! 3684: } ! 3685: ! 3686: SHEAD_UNLOCK (sheadp, prev_pl); ! 3687: } ! 3688: ! 3689: ! 3690: /* ! 3691: * This function encapsulates all user-level access to the front of the stream ! 3692: * head message queue. It deals with ensuring that the STREAMS scheduling ! 3693: * policy works (by managing QWANTR) and some other details such as dealing ! 3694: * with in-band processing of M_SIG messages. ! 3695: * ! 3696: * The stream head read queue should be frozen by the caller. ! 3697: */ ! 3698: ! 3699: #if __USE_PROTO__ ! 3700: __LOCAL__ mblk_t * (SHEAD_FIRSTMSG) (shead_t * sheadp) ! 3701: #else ! 3702: __LOCAL__ mblk_t * ! 3703: SHEAD_FIRSTMSG __ARGS ((sheadp)) ! 3704: shead_t * sheadp; ! 3705: #endif ! 3706: { ! 3707: mblk_t * msg; ! 3708: ! 3709: QFROZEN_TRACE (sheadp->sh_head, "SHEAD_FIRSTMSG"); ! 3710: ! 3711: while ((msg = sheadp->sh_head->q_first) != NULL) { ! 3712: ! 3713: if (msg->b_datap->db_type != M_SIG) ! 3714: return msg; ! 3715: ! 3716: rmvq (sheadp->sh_head, msg); ! 3717: SHEAD_SIGNAL (sheadp, * msg->b_rptr); ! 3718: freemsg (msg); ! 3719: } ! 3720: ! 3721: sheadp->sh_head->q_flag |= QWANTR; ! 3722: ! 3723: return NULL; ! 3724: } ! 3725: ! 3726: ! 3727: /* ! 3728: * This function does the necessary work to implement POLLWRBAND, which tests ! 3729: * to see if any of the previously written-to bands of flow in the next ! 3730: * downstream queue with a service procedure are not flow controlled. ! 3731: */ ! 3732: ! 3733: #if __USE_PROTO__ ! 3734: __LOCAL__ int (POLL_WRBAND) (queue_t * q) ! 3735: #else ! 3736: __LOCAL__ int ! 3737: POLL_WRBAND __ARGS ((q)) ! 3738: queue_t * q; ! 3739: #endif ! 3740: { ! 3741: pl_t prev_pl; ! 3742: qband_t * qbandp; ! 3743: ! 3744: prev_pl = QFREEZE_TRACE (q, "POLL_WRBAND"); ! 3745: ! 3746: do { ! 3747: q = QUEUE_NEXT (q); ! 3748: ! 3749: if (q == NULL) ! 3750: return 1; ! 3751: ! 3752: } while (q->q_qinfo->qi_srvp == NULL); ! 3753: ! 3754: ! 3755: /* ! 3756: * We have found a queue with a service procedure, and have it frozen. ! 3757: * If there are no bands, then we can write a band... ! 3758: */ ! 3759: ! 3760: if (q->q_nband == 0) { ! 3761: ! 3762: QUNFREEZE_TRACE (q, prev_pl); ! 3763: return 1; ! 3764: } ! 3765: ! 3766: qbandp = QUEUE_BAND (q, q->q_nband); ! 3767: ! 3768: ASSERT (qbandp != NULL); ! 3769: ! 3770: /* ! 3771: * Since if a band is blocked implies lower bands are blocked, we can ! 3772: * simply test the highest-numbered band. ! 3773: */ ! 3774: ! 3775: if ((qbandp->qb_flag & QB_FULL) != 0) { ! 3776: ! 3777: QUNFREEZE_TRACE (q, prev_pl); ! 3778: return 1; ! 3779: } ! 3780: ! 3781: ! 3782: /* ! 3783: * If all are full, request notification via back-enabling when the ! 3784: * highest band becomes writeable. ! 3785: */ ! 3786: ! 3787: qbandp->qb_flag |= QB_WANTW; ! 3788: ! 3789: QUNFREEZE_TRACE (q, prev_pl); ! 3790: return 0; ! 3791: } ! 3792: ! 3793: ! 3794: /* ! 3795: * This function has responsibility for checking to see whether the event mask ! 3796: * for this SIGPOLL request is immediately satisfied. ! 3797: */ ! 3798: ! 3799: #if __USE_PROTO__ ! 3800: __LOCAL__ short (SHEAD_POLL_CHECK) (shead_t * sheadp, short events) ! 3801: #else ! 3802: __LOCAL__ short ! 3803: SHEAD_POLL_CHECK __ARGS ((sheadp, events)) ! 3804: shead_t * sheadp; ! 3805: short events; ! 3806: #endif ! 3807: { ! 3808: short revents = 0; ! 3809: pl_t prev_pl; ! 3810: mblk_t * msg; ! 3811: ! 3812: ! 3813: /* ! 3814: * Check the conditions that do not depend on the status of the first ! 3815: * queued message (if any). ! 3816: * ! 3817: * For S_OUTPUT, using canputnext () is important because it sets the ! 3818: * back-enable flag so that we will be properly notified when the ! 3819: * condition becomes true. ! 3820: * ! 3821: * For S_WRBAND, things are a little more complex; this tests whether ! 3822: * *any* downstream priority band is writeable, which involves walking ! 3823: * over all the 'qband' structures allocated to the next stream with ! 3824: * a service procedure. ! 3825: */ ! 3826: ! 3827: if ((events & __POLL_OUTPUT) != 0 && canputnext (W (sheadp->sh_head))) ! 3828: revents |= __POLL_OUTPUT; ! 3829: ! 3830: if ((events & __POLL_WRBAND) != 0 && ! 3831: POLL_WRBAND (W (sheadp->sh_head))) ! 3832: revents |= __POLL_WRBAND; ! 3833: ! 3834: ! 3835: prev_pl = SHEAD_LOCK (sheadp); ! 3836: ! 3837: if ((events & S_ERROR) != 0 && ! 3838: (sheadp->sh_rerrcode != 0 || sheadp->sh_werrcode != 0)) ! 3839: revents |= POLLERR; ! 3840: ! 3841: if ((events & S_HANGUP) != 0 && (sheadp->sh_flags & SH_HANGUP) != 0) ! 3842: revents = (revents | POLLHUP) & ! 3843: ~ (__POLL_OUTPUT | __POLL_WRBAND); ! 3844: ! 3845: SHEAD_UNLOCK (sheadp, prev_pl); ! 3846: ! 3847: ! 3848: prev_pl = QFREEZE_TRACE (sheadp->sh_head, "SHEAD_POLL_CHECK"); ! 3849: ! 3850: if ((msg = SHEAD_FIRSTMSG (sheadp)) != NULL && ! 3851: datamsg (msg->b_datap->db_type)) { ! 3852: ! 3853: if (! pcmsg (msg->b_datap->db_type)) { ! 3854: ! 3855: if ((events & __POLL_INPUT) != 0) ! 3856: revents |= __POLL_INPUT; ! 3857: ! 3858: if ((events & __POLL_RDNORM) != 0 && msg->b_band == 0) ! 3859: revents |= __POLL_RDNORM; ! 3860: ! 3861: if ((events & __POLL_RDBAND) != 0 && msg->b_band > 0) ! 3862: revents |= __POLL_RDBAND; ! 3863: } else if ((events & __POLL_HIPRI) != 0) ! 3864: revents |= __POLL_HIPRI; ! 3865: } ! 3866: ! 3867: QUNFREEZE_TRACE (sheadp->sh_head, prev_pl); ! 3868: ! 3869: return revents; ! 3870: } ! 3871: ! 3872: ! 3873: /* ! 3874: * This function attempts to locate any sigpoll record for the current ! 3875: * process. The stream head needs to be locked out against modification of ! 3876: * the signal list, which means an IOCTL lock is sufficient. ! 3877: */ ! 3878: ! 3879: #if __USE_PROTO__ ! 3880: __LOCAL__ sigpoll_t * (FIND_SIGPOLL) (shead_t * sheadp) ! 3881: #else ! 3882: __LOCAL__ sigpoll_t * ! 3883: FIND_SIGPOLL __ARGS ((sheadp)) ! 3884: shead_t * sheadp; ! 3885: #endif ! 3886: { ! 3887: _VOID * proc; ! 3888: sigpoll_t * scan; ! 3889: ! 3890: ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK); ! 3891: ! 3892: /* ! 3893: * See if the process is already registered (so that we can modify or ! 3894: * free an existing record). ! 3895: */ ! 3896: ! 3897: proc = proc_ref (); ! 3898: ! 3899: for (scan = sheadp->sh_sigs ; scan != NULL ; scan ++) ! 3900: if (scan->sp_proc == proc) ! 3901: break; ! 3902: ! 3903: proc_unref (proc); ! 3904: ! 3905: return scan; ! 3906: } ! 3907: ! 3908: ! 3909: /* ! 3910: * This function deals with (de)registering a process for SIGPOLL. The caller ! 3911: * should have an IOCTL lock on the stream head so that there are no other ! 3912: * contexts which could modify the list of registered signals. ! 3913: */ ! 3914: ! 3915: #if __USE_PROTO__ ! 3916: __LOCAL__ int (REGISTER_SIGPOLL) (shead_t * sheadp, short events) ! 3917: #else ! 3918: __LOCAL__ int ! 3919: REGISTER_SIGPOLL __ARGS ((sheadp, events)) ! 3920: shead_t * sheadp; ! 3921: short events; ! 3922: #endif ! 3923: { ! 3924: _VOID * proc; ! 3925: sigpoll_t * scan; ! 3926: sigpoll_t * prev; ! 3927: ! 3928: ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK); ! 3929: ! 3930: /* ! 3931: * See if the process is already registered (so that we can modify or ! 3932: * free an existing record). We don't use the FIND_SIGPOLL () routine ! 3933: * because we want to locate the previous record also. ! 3934: */ ! 3935: ! 3936: proc = proc_ref (); ! 3937: ! 3938: for (prev = NULL, scan = sheadp->sh_sigs ; scan != NULL ; ! 3939: prev = scan, scan ++) { ! 3940: ! 3941: if (scan->sp_proc == proc) { ! 3942: /* ! 3943: * We have found a preexisting record... now modify ! 3944: * or free it. ! 3945: */ ! 3946: ! 3947: proc_unref (proc); ! 3948: ! 3949: (void) SHEAD_LOCK (sheadp); ! 3950: ! 3951: if ((scan->sp_events = events) == 0) { ! 3952: /* ! 3953: * Free the cell after unlinking it from the ! 3954: * list of registered processes. We take out ! 3955: * a lock on the stream head to protect ! 3956: * against streams-level contexts walking the ! 3957: * list. ! 3958: */ ! 3959: ! 3960: if (prev == NULL) ! 3961: sheadp->sh_sigs = scan->sp_next; ! 3962: else ! 3963: prev->sp_next = scan->sp_next; ! 3964: ! 3965: SHEAD_UNLOCK (sheadp, plbase); ! 3966: ! 3967: /* ! 3968: * We unlock the stream head before calling ! 3969: * the heap manager as a matter of courtesy. ! 3970: */ ! 3971: ! 3972: kmem_free (scan, sizeof (* scan)); ! 3973: proc_unref (proc); ! 3974: return 0; ! 3975: } ! 3976: ! 3977: SHEAD_UNLOCK (sheadp, plbase); ! 3978: goto sigcheck; ! 3979: } ! 3980: } ! 3981: ! 3982: ! 3983: if (events == 0) { ! 3984: /* ! 3985: * Not found, nothing to do. That is an error according to the ! 3986: * streamio (7) man pages. ! 3987: */ ! 3988: ! 3989: return EINVAL; ! 3990: } ! 3991: ! 3992: ! 3993: /* ! 3994: * We need to make a new event. ! 3995: */ ! 3996: ! 3997: if ((scan = (sigpoll_t *) kmem_alloc (sizeof (* scan), ! 3998: KM_SLEEP)) == NULL) { ! 3999: ! 4000: proc_unref (proc); ! 4001: return EAGAIN; ! 4002: } ! 4003: ! 4004: scan->sp_proc = proc; ! 4005: scan->sp_events = events; ! 4006: scan->sp_next = sheadp->sh_sigs; ! 4007: ! 4008: /* ! 4009: * Since we are the only process context modifying the list, we only ! 4010: * need to lock the last stage of the insert against interrupt-level ! 4011: * contexts walking the list. ! 4012: */ ! 4013: ! 4014: (void) SHEAD_LOCK (sheadp); ! 4015: ! 4016: sheadp->sh_sigs = scan; ! 4017: ! 4018: SHEAD_UNLOCK (sheadp, plbase); ! 4019: ! 4020: sigcheck: ! 4021: if ((events = SHEAD_POLL_CHECK (sheadp, scan->sp_events)) != 0) { ! 4022: /* ! 4023: * We have a winner! Check for the SIGURG special case, and ! 4024: * otherwise/also send SIGPOLL via proc_signal (). ! 4025: */ ! 4026: ! 4027: if ((events & __POLL_RDBAND) != 0 && ! 4028: (scan->sp_events & S_BANDURG) != 0) { ! 4029: ! 4030: proc_signal (scan->sp_proc, SIGURG); ! 4031: events &= ~ __POLL_RDBAND; ! 4032: } ! 4033: ! 4034: if (events != 0) ! 4035: proc_signal (scan->sp_proc, SIGPOLL); ! 4036: } ! 4037: ! 4038: return 0; ! 4039: } ! 4040: ! 4041: ! 4042: /* ! 4043: * This function maps a file descriptor into a stream head by calling upon the ! 4044: * abstract file-description functions declared in <sys/fhsys.h>. The caller ! 4045: * must lock the stream somehow. ! 4046: */ ! 4047: ! 4048: #if ! _NO_INSTALLABLE_FILESYSTEMS ! 4049: ! 4050: extern fprocs_t streams_fsys; ! 4051: ! 4052: #endif ! 4053: ! 4054: ! 4055: #if __USE_PROTO__ ! 4056: __LOCAL__ shead_t * (FH_TO_STREAM) (int fd, int * retvalp) ! 4057: #else ! 4058: __LOCAL__ shead_t * ! 4059: FH_TO_STREAM __ARGS ((fd, retvalp)) ! 4060: int fd; ! 4061: int * retvalp; ! 4062: #endif ! 4063: { ! 4064: fhandle_t * handle; ! 4065: scookie_t * cookie; ! 4066: ! 4067: ASSERT (retvalp != NULL); ! 4068: ! 4069: if ((handle = fd_get_handle (fd)) == NULL) { ! 4070: ! 4071: * retvalp = EBADF; ! 4072: return NULL; ! 4073: #if ! _NO_INSTALLABLE_FILESYSTEMS ! 4074: } else if (fh_procs (handle) == & streams_fsys) { ! 4075: ! 4076: * retvalp = EINVAL; ! 4077: return NULL; ! 4078: #endif ! 4079: } ! 4080: ! 4081: cookie = (scookie_t *) fh_get_cookie (handle); ! 4082: ! 4083: ASSERT (cookie != NULL); ! 4084: ! 4085: if (cookie->sheadp == NULL) ! 4086: cmn_err (CE_WARN, "Bad cookie in streams"); ! 4087: ! 4088: return cookie->sheadp; ! 4089: } ! 4090: ! 4091: ! 4092: /* ! 4093: * The following structure is used by the routines below to deal with the ! 4094: * M_PASSFP message type. The structure of the data contained in that message ! 4095: * is completely opaque to STREAMS routines, so we keep the definition local. ! 4096: */ ! 4097: ! 4098: struct passfp { ! 4099: sftab_t * sftab; /* system file table entry address */ ! 4100: n_uid_t uid; ! 4101: n_gid_t gid; ! 4102: }; ! 4103: ! 4104: ! 4105: /* ! 4106: * This function attempts to retrieve a file descriptor sent by an I_SENDFD ! 4107: * ioctl () and create a local file descriptor referring to the same file. ! 4108: */ ! 4109: ! 4110: #if __USE_PROTO__ ! 4111: __LOCAL__ int (FH_RECV) (shead_t * sheadp, int mode, struct strrecvfd * recvp) ! 4112: #else ! 4113: __LOCAL__ int ! 4114: FH_RECV __ARGS ((sheadp, mode, recvp)) ! 4115: shead_t * sheadp; ! 4116: int mode; ! 4117: struct strrecvfd ! 4118: * recvp; ! 4119: #endif ! 4120: { ! 4121: mblk_t * msg; ! 4122: struct passfp * fp; ! 4123: int retval; ! 4124: ! 4125: ASSERT (sheadp != NULL); ! 4126: ASSERT (recvp != NULL); ! 4127: ! 4128: if (! SHEAD_IS_PIPE (sheadp)) ! 4129: return EINVAL; ! 4130: ! 4131: if ((mode & FREAD) == 0) ! 4132: return EBADF; ! 4133: ! 4134: mode &= ~ FWRITE; ! 4135: ! 4136: ! 4137: /* ! 4138: * Look at the stream head to see if a message is present. ! 4139: */ ! 4140: ! 4141: for (;;) { ! 4142: int retval; ! 4143: ! 4144: (void) QFREEZE_TRACE (sheadp->sh_head, "FH_RECV"); ! 4145: ! 4146: if ((msg = SHEAD_FIRSTMSG (sheadp)) != NULL) ! 4147: break; ! 4148: ! 4149: /* ! 4150: * Use the STREAMS flag to indicate that we have found the ! 4151: * queue empty. ! 4152: */ ! 4153: ! 4154: (void) SHEAD_LOCK (sheadp); ! 4155: ! 4156: QUNFREEZE_TRACE (sheadp->sh_head, plstr); ! 4157: ! 4158: /* ! 4159: * We need to wait (unless O_NDELAY or O_NONBLOCK has been ! 4160: * specified), or the stream has been hung up. ! 4161: */ ! 4162: ! 4163: if ((retval = SHEAD_WAIT_NONBLOCK (sheadp, mode, SH_READ_WAIT, ! 4164: CHECK_SIGNALS)) != 0) ! 4165: return retval; ! 4166: ! 4167: /* ! 4168: * Check again... ! 4169: */ ! 4170: } ! 4171: ! 4172: if (msg->b_datap->db_type != M_PASSFP) ! 4173: retval = EBADMSG; ! 4174: else if (! fd_can_add ()) ! 4175: retval = EMFILE; ! 4176: else { ! 4177: ! 4178: retval = 0; ! 4179: rmvq (sheadp->sh_head, msg); ! 4180: } ! 4181: ! 4182: QUNFREEZE_TRACE (sheadp->sh_head, plbase); ! 4183: ! 4184: if (retval != 0) ! 4185: return retval; ! 4186: ! 4187: /* ! 4188: * After this point, "msg" is our responsibility and we either have to ! 4189: * free it or put it back if there is an error. ! 4190: */ ! 4191: ! 4192: fp = (struct passfp *) msg->b_rptr; ! 4193: ! 4194: if ((retval = fd_add_sftab (fp->sftab, & recvp->fd)) == 0 && ! 4195: ((recvp->uid = (o_uid_t) fp->uid) != fp->uid || ! 4196: (recvp->gid = (o_gid_t) fp->gid) != fp->gid)) ! 4197: retval = EOVERFLOW; ! 4198: ! 4199: freemsg (msg); ! 4200: return retval; ! 4201: } ! 4202: ! 4203: ! 4204: /* ! 4205: * This function attempts to send a file descriptor to another process at the ! 4206: * other end of a stream pipe. ! 4207: */ ! 4208: ! 4209: #if __USE_PROTO__ ! 4210: __LOCAL__ int (FH_SEND) (shead_t * sheadp, int fd, cred_t * credp) ! 4211: #else ! 4212: __LOCAL__ int ! 4213: FH_SEND __ARGS ((sheadp, fd, credp)) ! 4214: shead_t * sheadp; ! 4215: int fd; ! 4216: cred_t * credp; ! 4217: #endif ! 4218: { ! 4219: mblk_t * msg; ! 4220: struct passfp * fp; ! 4221: sftab_t * sftab; ! 4222: shead_t * other; ! 4223: int retval; ! 4224: ! 4225: ASSERT (sheadp != NULL); ! 4226: ASSERT (credp != NULL); ! 4227: ! 4228: if (! SHEAD_IS_PIPE (sheadp)) ! 4229: return EINVAL; ! 4230: ! 4231: /* ! 4232: * We are passed a file descriptor (a user-level abstract entity); ! 4233: * here we turn that into a kernel-level abstract entity. ! 4234: */ ! 4235: ! 4236: if ((sftab = fd_get_sftab (fd)) == NULL) ! 4237: return EBADF; ! 4238: ! 4239: other = SHEAD_OTHER (sheadp); ! 4240: ! 4241: if (! canput (W (other->sh_head)) || ! 4242: (msg = MSGB_ALLOC (sizeof (* fp), BPRI_LO, KM_SLEEP)) == NULL) ! 4243: return EAGAIN; ! 4244: ! 4245: /* ! 4246: * Fill in the new message block and put the message to the other ! 4247: * side. After this point we have to free the message block if there ! 4248: * is a problem. ! 4249: */ ! 4250: ! 4251: fp = (struct passfp *) msg->b_rptr; ! 4252: msg->b_wptr = (unsigned char *) (fp + 1); ! 4253: ! 4254: msg->b_datap->db_type = M_PASSFP; ! 4255: ! 4256: fp->sftab = sftab; ! 4257: fp->uid = credp->cr_uid; ! 4258: fp->gid = credp->cr_gid; ! 4259: ! 4260: (void) SHEAD_LOCK (sheadp); ! 4261: ! 4262: if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, FWRITE)) == 0) { ! 4263: ! 4264: putq (W (other->sh_head), msg); ! 4265: ! 4266: SHEAD_UNLOCK (sheadp, plbase); ! 4267: } else ! 4268: freemsg (msg); ! 4269: ! 4270: return retval; ! 4271: } ! 4272: ! 4273: ! 4274: /* ! 4275: * This function factors out the details of copying data out from kernel space ! 4276: * into a "strbuf" stream buffer structure in user space. ! 4277: * ! 4278: * The return value of this function is 0 on success or -1 on error. ! 4279: */ ! 4280: ! 4281: enum { ! 4282: CONTROL_PART, ! 4283: DATA_PART ! 4284: }; ! 4285: ! 4286: #if __USE_PROTO__ ! 4287: __LOCAL__ int (COPYOUT_BUF) (struct strbuf * bufp, mblk_t ** mpp, int data) ! 4288: #else ! 4289: __LOCAL__ int ! 4290: COPYOUT_BUF __ARGS ((bufp, mpp, data)) ! 4291: struct strbuf * bufp; ! 4292: mblk_t ** mpp; ! 4293: int data; ! 4294: #endif ! 4295: { ! 4296: mblk_t * prev; ! 4297: mblk_t * scan; ! 4298: int remaining; ! 4299: caddr_t outaddr; ! 4300: ! 4301: ASSERT (mpp != NULL); ! 4302: ! 4303: /* ! 4304: * The first thing we do is check some special values; if a "strbuf" ! 4305: * entry is NULL or has its "maxlen" member set to "-1", we do nothing ! 4306: * with the message. ! 4307: */ ! 4308: ! 4309: if (bufp == NULL || bufp->maxlen == -1) ! 4310: return 0; ! 4311: ! 4312: /* ! 4313: * Next, if this is a data-part copy, skip any intial M_PROTO or ! 4314: * M_PCPROTO message blocks. There *should* only ever be one of these ! 4315: * at the front of a message, but we are required to effectively ! 4316: * coalesce multiple control blocks. ! 4317: */ ! 4318: ! 4319: prev = NULL; ! 4320: scan = * mpp; ! 4321: ! 4322: if (data == DATA_PART) { ! 4323: /* ! 4324: * Find the data portion of the message, if any. ! 4325: */ ! 4326: ! 4327: while (scan != NULL) { ! 4328: ! 4329: if (scan->b_datap->db_type == M_DATA) ! 4330: break; ! 4331: scan = (prev = scan)->b_cont; ! 4332: } ! 4333: } else ! 4334: if (scan->b_datap->db_type == M_DATA) ! 4335: scan = NULL; ! 4336: ! 4337: /* ! 4338: * If there is no control (or data, as appropriate) part to the ! 4339: * message, then we set the "len" member of the "strbuf" to -1. ! 4340: */ ! 4341: ! 4342: if (scan == NULL) { ! 4343: ! 4344: bufp->len = -1; ! 4345: return 0; ! 4346: } ! 4347: ! 4348: ! 4349: /* ! 4350: * Now be do the actual copy; the form of this loop is organized so ! 4351: * that zero-length message blocks will be consumed if "maxlen" is ! 4352: * set to 0. This is important not only to comply with the manual page ! 4353: * for getmsg ()/getpmsg (), but also ensures that trailing zero- ! 4354: * length blocks at the end of a message get cleaned up properly. ! 4355: */ ! 4356: ! 4357: bufp->len = 0; ! 4358: remaining = bufp->maxlen; ! 4359: outaddr = (caddr_t) bufp->buf; ! 4360: ! 4361: for (;;) { ! 4362: size_t copylen = scan->b_wptr - scan->b_rptr; ! 4363: mblk_t * next; ! 4364: ! 4365: if (copylen > remaining) ! 4366: copylen = remaining; ! 4367: ! 4368: if (copylen > 0) { ! 4369: /* ! 4370: * Copy the data to the user. Don't forget that ! 4371: * copyout () is like bcopy () in that the arguments ! 4372: * are src, dest, len ! ! 4373: */ ! 4374: ! 4375: if (copyout (scan->b_rptr, outaddr, copylen) != 0) ! 4376: return EFAULT; ! 4377: ! 4378: bufp->len += copylen; ! 4379: scan->b_rptr += copylen; ! 4380: remaining -= copylen; ! 4381: } ! 4382: ! 4383: if (scan->b_rptr != scan->b_wptr) { ! 4384: /* ! 4385: * Since this message block was not fully consumed, we ! 4386: * can infer that we have copied all the data we can. ! 4387: */ ! 4388: ! 4389: ASSERT (remaining == 0); ! 4390: break; ! 4391: } ! 4392: ! 4393: ! 4394: /* ! 4395: * This message block has been consumed; unlink and free it. ! 4396: */ ! 4397: ! 4398: next = scan->b_cont; ! 4399: if (prev == NULL) ! 4400: * mpp = next; ! 4401: else ! 4402: prev->b_cont = next; ! 4403: freeb (scan); ! 4404: ! 4405: ! 4406: /* ! 4407: * Get ready to go around the loop again; if we are copying ! 4408: * the control part of a message, we have to test for the end ! 4409: * of the control part here. ! 4410: */ ! 4411: ! 4412: if ((scan = next) == NULL) ! 4413: break; ! 4414: ! 4415: if (data == CONTROL_PART && scan->b_datap->db_type == M_DATA) ! 4416: break; ! 4417: } ! 4418: ! 4419: return 0; ! 4420: } ! 4421: ! 4422: ! 4423: /* ! 4424: * This is a buffer callback function used by SHEAD_PEEK () to deal with ! 4425: * dupmsg () failures via bufcall (). ! 4426: */ ! 4427: ! 4428: #if __USE_PROTO__ ! 4429: __LOCAL__ void peek_bufcall_func (_VOID * arg) ! 4430: #else ! 4431: __LOCAL__ void ! 4432: peek_bufcall_func (arg) ! 4433: _VOID * arg; ! 4434: #endif ! 4435: { ! 4436: pl_t prev_pl; ! 4437: shead_t * sheadp = (shead_t *) arg; ! 4438: ! 4439: /* ! 4440: * We freeze the stream head read queue to synchronize ourselves with ! 4441: * the SHEAD_PEEK () and avoid race conditions where we try and wake ! 4442: * up the process that scheduled us before they have slept. ! 4443: */ ! 4444: ! 4445: prev_pl = QFREEZE_TRACE (sheadp->sh_head, "peek_bufcall_func"); ! 4446: ! 4447: sheadp->sh_read_bufcall = 0; ! 4448: ! 4449: SHEAD_WAKE (sheadp, SH_PEEK_WAIT); ! 4450: ! 4451: QUNFREEZE_TRACE (sheadp->sh_head, prev_pl); ! 4452: } ! 4453: ! 4454: ! 4455: /* ! 4456: * This is a helper function for I_PEEK and read ()-like functions who want ! 4457: * to recover from an out-of-memory situation by performing a short sleep. ! 4458: * ! 4459: * This function takes care of scheduling and cancelling the bufcall. The ! 4460: * caller must have the stream head locked when calling this function. ! 4461: * ! 4462: * This function returns with the stream head read queue unlocked, and with ! 4463: * the value 0 on success and an error number on error. ! 4464: */ ! 4465: ! 4466: #if __USE_PROTO__ ! 4467: __LOCAL__ int (SHEAD_READ_BUFCALL) (shead_t * sheadp, int __NOTUSED (mode)) ! 4468: #else ! 4469: __LOCAL__ int ! 4470: SHEAD_READ_BUFCALL __ARGS ((sheadp, mode)) ! 4471: shead_t * sheadp; ! 4472: int mode; ! 4473: #endif ! 4474: { ! 4475: SHEAD_ASSERT_LOCKED (sheadp); ! 4476: ! 4477: if (sheadp->sh_read_bufcall == 0 && ! 4478: (sheadp->sh_read_bufcall = bufcall (1024, BPRI_LO, ! 4479: peek_bufcall_func, ! 4480: sheadp)) == 0) { ! 4481: SHEAD_UNLOCK (sheadp, plbase); ! 4482: return ENOSR; ! 4483: } ! 4484: ! 4485: return SHEAD_WAIT_NONBLOCK (sheadp, FREAD, SH_PEEK_WAIT, ! 4486: CHECK_SIGNALS); ! 4487: } ! 4488: ! 4489: ! 4490: /* ! 4491: * This function implements I_PEEK read-ahead for streams. The caller should ! 4492: * have the stream head locked for read/write access. ! 4493: */ ! 4494: ! 4495: #if __USE_PROTO__ ! 4496: __LOCAL__ int (SHEAD_PEEK) (shead_t * sheadp, struct strpeek * peek, ! 4497: int * rvalp) ! 4498: #else ! 4499: __LOCAL__ int ! 4500: SHEAD_PEEK __ARGS ((sheadp, peek, rvalp)) ! 4501: shead_t * sheadp; ! 4502: struct strpeek * peek; ! 4503: int * rvalp; ! 4504: #endif ! 4505: { ! 4506: mblk_t * msg; ! 4507: int retval; ! 4508: ! 4509: ASSERT (sheadp != NULL); ! 4510: ASSERT (peek != NULL); ! 4511: ASSERT (rvalp != NULL); ! 4512: ! 4513: if (peek->flags != 0 && peek->flags != RS_HIPRI) ! 4514: return EINVAL; ! 4515: ! 4516: /* ! 4517: * Look at the stream head to see if there are any queued messages. ! 4518: * ! 4519: * Some notes about this are in order; as mentioned in the discussion ! 4520: * on locking elsewhere, the possibility of page fault resolution ! 4521: * during copies to user space complicates life, because copy routines ! 4522: * may sleep while a page is made resident. ! 4523: * ! 4524: * This affects routines which read from the stream head in various ! 4525: * ways, some of which are outlined in the general section on locking. ! 4526: * Other than data consistency, it also affects the way message are ! 4527: * deallocated; this routine wants to take a copy of the data in a ! 4528: * message, but we need to ensure that the message will not be ! 4529: * deallocated not just by other processes but also by actions at the ! 4530: * stream level such as M_FLUSH. ! 4531: * ! 4532: * Other than getting into a web of locking flags and reference counts ! 4533: * (there are already too many of those), the simplest ways of dealing ! 4534: * with this are a) create a duplicate reference to the message data ! 4535: * with dupmsg (), and b) simply dequeue the message and put it back ! 4536: * when we're done. ! 4537: * ! 4538: * Neither alternative is without unpleasant consequences; a) has to ! 4539: * deal with a lack of available storage to duplicate the message ! 4540: * blocks, and b) has to deal with such things as reads blocking while ! 4541: * the message is dequeued. ! 4542: * ! 4543: * a) and b) seem to have more-or-less equal implementation costs, but ! 4544: * while a) is guaranteed to maintain the semantics of all stream ! 4545: * operations, b) is not. Unless we can predict all the consequences ! 4546: * of b) and either work around them or determine that they are benign ! 4547: * then a) seems preferable. ! 4548: */ ! 4549: ! 4550: for (;;) { ! 4551: (void) QFREEZE_TRACE (sheadp->sh_head, "SHEAD_PEEK"); ! 4552: ! 4553: if ((msg = SHEAD_FIRSTMSG (sheadp)) == NULL) { ! 4554: no_message: ! 4555: /* ! 4556: * No go; arrange for the value 0 to be returned to ! 4557: * the caller of the ioctl (). ! 4558: */ ! 4559: ! 4560: QUNFREEZE_TRACE (sheadp->sh_head, plbase); ! 4561: * rvalp = 0; ! 4562: ! 4563: return 0; ! 4564: } ! 4565: ! 4566: switch (msg->b_datap->db_type) { ! 4567: ! 4568: case M_DATA: ! 4569: case M_PROTO: ! 4570: /* ! 4571: * If the caller has asked for high-priority messages ! 4572: * only, then we arrange to return 0. ! 4573: */ ! 4574: ! 4575: if ((peek->flags & RS_HIPRI) != 0) ! 4576: goto no_message; ! 4577: break; ! 4578: ! 4579: case M_PCPROTO: ! 4580: break; ! 4581: ! 4582: default: ! 4583: QUNFREEZE_TRACE (sheadp->sh_head, plbase); ! 4584: return EBADMSG; ! 4585: } ! 4586: ! 4587: ! 4588: /* ! 4589: * Attempt to obtain a duplicate reference to this message. ! 4590: */ ! 4591: ! 4592: if ((msg = dupmsg (msg)) != NULL) { ! 4593: ! 4594: QUNFREEZE_TRACE (sheadp->sh_head, plbase); ! 4595: break; ! 4596: } ! 4597: ! 4598: ! 4599: /* ! 4600: * Wait a short time for buffers to be available. To do this, ! 4601: * we transfer our locking attention from the queue to the ! 4602: * stream head. ! 4603: */ ! 4604: ! 4605: (void) SHEAD_LOCK (sheadp); ! 4606: ! 4607: QUNFREEZE_TRACE (sheadp->sh_head, plstr); ! 4608: ! 4609: if ((retval = SHEAD_READ_BUFCALL (sheadp, FREAD)) != 0) ! 4610: return retval; ! 4611: } ! 4612: ! 4613: ! 4614: /* ! 4615: * Now we have a duplicate copy of a message to transfer to user ! 4616: * space. From this point on, any attempt to exit from this routine ! 4617: * must take care of freeing this message. However, we don't have to ! 4618: * touch the queue again. ! 4619: */ ! 4620: ! 4621: peek->flags = msg->b_datap->db_type == M_PCPROTO ? RS_HIPRI : 0; ! 4622: ! 4623: retval = (COPYOUT_BUF (& peek->ctlbuf, & msg, CONTROL_PART) != 0 || ! 4624: COPYOUT_BUF (& peek->databuf, & msg, ! 4625: DATA_PART) != 0) ? EFAULT : 0; ! 4626: ! 4627: if (msg != NULL) ! 4628: freemsg (msg); ! 4629: ! 4630: * rvalp = 1; ! 4631: ! 4632: return retval; ! 4633: } ! 4634: ! 4635: ! 4636: /* ! 4637: * Helper function to atomically read the stream head write offset. ! 4638: */ ! 4639: ! 4640: #if __USE_PROTO__ ! 4641: __LOCAL__ short (SHEAD_WRITEOFFSET) (shead_t * sheadp) ! 4642: #else ! 4643: __LOCAL__ short ! 4644: SHEAD_WRITEOFFSET __ARGS ((sheadp)) ! 4645: shead_t * sheadp; ! 4646: #endif ! 4647: { ! 4648: pl_t prev_pl; ! 4649: short opt; ! 4650: ! 4651: prev_pl = SHEAD_LOCK (sheadp); ! 4652: ! 4653: opt = sheadp->sh_readopt; ! 4654: ! 4655: SHEAD_UNLOCK (sheadp, prev_pl); ! 4656: ! 4657: return opt; ! 4658: } ! 4659: ! 4660: ! 4661: /* ! 4662: * This function tests for errors on a stream and optionally also waits for ! 4663: * flow control to be relieved. ! 4664: */ ! 4665: ! 4666: #if __USE_PROTO__ ! 4667: __LOCAL__ int (SHEAD_WRITE_TEST) (shead_t * sheadp, int mode, int band, ! 4668: int hipri) ! 4669: #else ! 4670: __LOCAL__ int ! 4671: SHEAD_WRITE_TEST __ARGS ((sheadp, mode, band, hipri)) ! 4672: shead_t * sheadp; ! 4673: int mode; ! 4674: int band; ! 4675: int hipri; ! 4676: #endif ! 4677: { ! 4678: int retval; ! 4679: ! 4680: do { ! 4681: (void) SHEAD_LOCK (sheadp); ! 4682: ! 4683: if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, mode)) != 0) ! 4684: break; ! 4685: ! 4686: if (hipri != 0 || bcanputnext (W (sheadp->sh_head), band)) { ! 4687: ! 4688: SHEAD_UNLOCK (sheadp, plbase); ! 4689: break; ! 4690: } ! 4691: } while ((retval = SHEAD_WAIT_NONBLOCK (sheadp, mode, SH_WRITE_WAIT, ! 4692: CHECK_SIGNALS)) == 0); ! 4693: ! 4694: return retval; ! 4695: } ! 4696: ! 4697: ! 4698: /* ! 4699: * This function deals with all the grunge of creating a message for sending ! 4700: * down a stream. There are many conditions that need to be checked, including ! 4701: * whether the message fits within the size limits given by the downstream ! 4702: * queue. ! 4703: * ! 4704: * Since the message is going to be written to the stream, we also deal with ! 4705: * waiting for flow control here. We only allocate memory for the user's data ! 4706: * when we have an indication that it will be valid to write it... this may ! 4707: * not be an optimal choice for a high-performance system with vast amounts ! 4708: * of STREAMS buffer space. ! 4709: */ ! 4710: ! 4711: #if __USE_PROTO__ ! 4712: __LOCAL__ mblk_t * (SHEAD_MAKEMSG) (shead_t * sheadp, int mode, ! 4713: struct strbuf * ctlbuf, ! 4714: struct strbuf * databuf, ! 4715: int flags, int band, int * retvalp) ! 4716: #else ! 4717: __LOCAL__ mblk_t * ! 4718: SHEAD_MAKEMSG __ARGS ((sheadp, mode, ctlbuf, databuf, flags, band, retvalp)) ! 4719: shead_t * sheadp; ! 4720: int mode; ! 4721: struct strbuf * ctlbuf; ! 4722: struct strbuf * databuf; ! 4723: int flags; ! 4724: int band; ! 4725: int * retvalp; ! 4726: #endif ! 4727: { ! 4728: queue_t * q; ! 4729: int ctlsize; ! 4730: int datasize; ! 4731: int wroff; ! 4732: mblk_t * ctlmsg; ! 4733: mblk_t * datamsg; ! 4734: ! 4735: ASSERT (sheadp != NULL); ! 4736: ASSERT (retvalp != NULL); ! 4737: ! 4738: /* ! 4739: * The "flags" value specifies one of the constants MSG_BAND or ! 4740: * MSG_HIPRI. Despite being arranged as flags, only one is allowed to ! 4741: * be given. ! 4742: */ ! 4743: ! 4744: if (flags != MSG_BAND && flags != MSG_HIPRI) { ! 4745: ! 4746: * retvalp = EINVAL; ! 4747: return NULL; ! 4748: } ! 4749: ! 4750: if ((mode & FWRITE) == 0) { ! 4751: ! 4752: * retvalp = EBADF; ! 4753: return NULL; ! 4754: } ! 4755: ! 4756: mode &= ~ FREAD; ! 4757: ! 4758: ! 4759: /* ! 4760: * The absolute maximum possible size for the control or data parts of ! 4761: * a STREAMS message are configured system-wide. ! 4762: */ ! 4763: ! 4764: ctlsize = ctlbuf == NULL ? -1 : ctlbuf->len; ! 4765: datasize = databuf == NULL ? -1 : databuf->len; ! 4766: wroff = SHEAD_WRITEOFFSET (sheadp); ! 4767: ! 4768: q = TOP_QUEUE (sheadp); ! 4769: ! 4770: if (ctlsize > str_mem->sm_maxctlsize || ! 4771: (datasize + wroff) > str_mem->sm_maxdatasize || ! 4772: (datasize + wroff) < q->q_minpsz || ! 4773: (datasize + wroff) > q->q_maxpsz) { ! 4774: ! 4775: * retvalp = ERANGE; ! 4776: return NULL; ! 4777: } ! 4778: ! 4779: ! 4780: /* ! 4781: * You can't send a high-priority message without a control part, or a ! 4782: * high-priority message with a non-zero band number. ! 4783: * ! 4784: * Otherwise, if no data at all is specified, then no message will be ! 4785: * sent. ! 4786: */ ! 4787: ! 4788: if (flags == MSG_HIPRI) { ! 4789: ! 4790: if (ctlsize < 0 || band != 0) { ! 4791: ! 4792: * retvalp = EINVAL; ! 4793: return NULL; ! 4794: } ! 4795: } else if (datasize < 0 && ctlsize < 0) { ! 4796: ! 4797: * retvalp = 0; ! 4798: return NULL; ! 4799: } ! 4800: ! 4801: ! 4802: /* ! 4803: * Let's see if the stream is flow controlled; if it is, we either ! 4804: * block or return EAGAIN depending on the FNDELAY/FNONBLOCK setting. ! 4805: */ ! 4806: ! 4807: if ((* retvalp = SHEAD_WRITE_TEST (sheadp, mode, band, flags)) != 0) ! 4808: return NULL; ! 4809: ! 4810: /* ! 4811: * Now we allocate data space for the messages. If the size of a ! 4812: * component is -1, then we don't allocate any space for that part, ! 4813: * otherwise we allocate a component of length 0. ! 4814: * ! 4815: * Don't forget that copyin () has arguments in the bcopy () order, ! 4816: * ie. src, dest, len ! 4817: */ ! 4818: ! 4819: if (ctlsize >= 0) { ! 4820: /* ! 4821: * Special case; the stream head is required to ensure that ! 4822: * the control part of any message has at least 64 bytes of ! 4823: * space. This is specified in the putmsg (2) manual page! ! 4824: */ ! 4825: ! 4826: if ((ctlmsg = MSGB_ALLOC (ctlsize < 64 ? 64 : ctlsize, ! 4827: BPRI_LO, KM_SLEEP)) == NULL) { ! 4828: * retvalp = ENOSR; ! 4829: return NULL; ! 4830: } ! 4831: ! 4832: ctlmsg->b_datap->db_type = flags == MSG_HIPRI ? M_PCPROTO : ! 4833: M_PROTO; ! 4834: ctlmsg->b_band = band; ! 4835: ! 4836: if (ctlsize > 0 && ! 4837: copyin (ctlbuf->buf, ctlmsg->b_rptr, ctlsize) != 0) { ! 4838: ! 4839: freeb (ctlmsg); ! 4840: * retvalp = EFAULT; ! 4841: return NULL; ! 4842: } ! 4843: ! 4844: ctlmsg->b_wptr += ctlsize; ! 4845: } else ! 4846: ctlmsg = NULL; /* paranoia */ ! 4847: ! 4848: if (datasize >= 0) { ! 4849: ! 4850: if ((datamsg = MSGB_ALLOC (datasize + wroff, BPRI_LO, ! 4851: KM_SLEEP)) == NULL) { ! 4852: if (ctlsize >= 0) ! 4853: freeb (ctlmsg); ! 4854: ! 4855: * retvalp = ENOSR; ! 4856: return NULL; ! 4857: } ! 4858: ! 4859: if (ctlsize < 0) ! 4860: ctlmsg = datamsg; ! 4861: else ! 4862: ctlmsg->b_cont = datamsg; ! 4863: ! 4864: datamsg->b_band = band; ! 4865: datamsg->b_wptr = datamsg->b_wptr = datamsg->b_rptr + wroff; ! 4866: ! 4867: if (datasize > 0 && ! 4868: copyin (databuf->buf, datamsg->b_rptr, datasize) != 0) { ! 4869: ! 4870: freemsg (ctlmsg); ! 4871: ! 4872: * retvalp = EFAULT; ! 4873: return NULL; ! 4874: } ! 4875: ! 4876: datamsg->b_wptr += datasize; ! 4877: } ! 4878: ! 4879: ! 4880: /* ! 4881: * Since the allocation requests could have blocked for memory to ! 4882: * become available, and the copy requests could have blocked to ! 4883: * resolve page faults, we could actually be a fair way down the track ! 4884: * by now. ! 4885: * ! 4886: * If we were paranoid, we would recheck the flow control parameters ! 4887: * and a bunch of other stuff, but there doesn't seem to be a whole ! 4888: * lot of point to that. As long as we don't use data that could have ! 4889: * changed while we waited, we're fine. ! 4890: */ ! 4891: ! 4892: * retvalp = 0; ! 4893: return ctlmsg; ! 4894: } ! 4895: ! 4896: ! 4897: /* ! 4898: * This function implements the I_FDINSERT ioctl (). ! 4899: */ ! 4900: ! 4901: #if __USE_PROTO__ ! 4902: __LOCAL__ int (SHEAD_FDINSERT) (shead_t * sheadp, int mode, ! 4903: struct strfdinsert * fdinsp) ! 4904: #else ! 4905: __LOCAL__ int ! 4906: SHEAD_FDINSERT __ARGS ((sheadp, mode, fdinsp)) ! 4907: shead_t * sheadp; ! 4908: int mode; ! 4909: struct strfdinsert ! 4910: * fdinsp; ! 4911: #endif ! 4912: { ! 4913: int retval; ! 4914: shead_t * other; ! 4915: mblk_t * msg; ! 4916: ! 4917: ASSERT (sheadp != NULL); ! 4918: ASSERT (fdinsp != NULL); ! 4919: ! 4920: /* ! 4921: * There are a large number of error conditions to check for this ! 4922: * function. Don't lose sight of the fact that the big set of chained ! 4923: * conditions below computes "other" for us. ! 4924: */ ! 4925: /* ! 4926: * ALIGNMENT-DEPENDENT CODE. ! 4927: */ ! 4928: ! 4929: if ((fdinsp->flags != 0 && fdinsp->flags != RS_HIPRI) || ! 4930: ((unsigned) fdinsp->offset & ~ sizeof (int)) != 0 || ! 4931: fdinsp->offset + sizeof (queue_t *) > fdinsp->ctlbuf.len || ! 4932: (other = FH_TO_STREAM (fdinsp->fildes, & retval)) != 0) { ! 4933: /* ! 4934: * A failure of any of the above returns EINVAL; according to ! 4935: * streamio (7) EINVAL rather than EBADF results from a bad ! 4936: * file descriptor. ! 4937: */ ! 4938: ! 4939: return EINVAL; ! 4940: } ! 4941: ! 4942: /* ! 4943: * Make a band 0 message (possibly high-priority). This can fail if ! 4944: * the requested message is too large for the advertised limits set ! 4945: * by the next thing downstream. ! 4946: * ! 4947: * IMPORANT: we *rely* on this function making a message with a single ! 4948: * large control block at least as big as the advertised size. If we ! 4949: * cannot rely on this function we have to do lots of extra checking ! 4950: * which I'd rather avoid. ! 4951: */ ! 4952: ! 4953: msg = SHEAD_MAKEMSG (sheadp, mode, & fdinsp->ctlbuf, ! 4954: & fdinsp->databuf, ! 4955: fdinsp->flags ? MSG_HIPRI : MSG_BAND, 0, ! 4956: & retval); ! 4957: if (msg == NULL) ! 4958: return retval; ! 4959: ! 4960: /* ! 4961: * Note that we don't recheck for hangups even though we could have ! 4962: * waited a poentially long time in SHEAD_MAKEMSG (). The hangup ! 4963: * condition has plenty of slop in it with the time it takes write ! 4964: * messages to move down the queue anyway; drivers and modules have to ! 4965: * be able to cope. ! 4966: */ ! 4967: ! 4968: * (queue_t **) (msg->b_rptr + fdinsp->offset) = other->sh_head; ! 4969: ! 4970: putq (W (sheadp->sh_head), msg); ! 4971: ! 4972: return 0; ! 4973: } ! 4974: ! 4975: ! 4976: /* ! 4977: * This function implements the I_FIND ioctl (). ! 4978: */ ! 4979: ! 4980: #if __USE_PROTO__ ! 4981: __LOCAL__ int (SHEAD_FIND_MODINFO) (shead_t * sheadp, char * modname, ! 4982: int * rvalp) ! 4983: #else ! 4984: __LOCAL__ int ! 4985: SHEAD_FIND_MODINFO __ARGS ((sheadp, modname, rvalp)) ! 4986: shead_t * sheadp; ! 4987: char * modname; ! 4988: int * rvalp; ! 4989: #endif ! 4990: { ! 4991: modsw_t * module; ! 4992: ! 4993: /* ! 4994: * First try to find the module in the global list of modules, then ! 4995: * attempt to find that module's info on the stream. ! 4996: */ ! 4997: ! 4998: if ((module = FIND_MODULE (modname)) == NULL) ! 4999: return EINVAL; ! 5000: else { ! 5001: queue_t * scan; ! 5002: pl_t prev_pl; ! 5003: ! 5004: /* ! 5005: * Walk down the write side of the stream until either the ! 5006: * write side module info matches -or- a cross-point is found. ! 5007: */ ! 5008: ! 5009: scan = W (sheadp->sh_head); ! 5010: ! 5011: prev_pl = SHEAD_LOCK (sheadp); ! 5012: ! 5013: while (scan->q_next != NULL) { ! 5014: if ((scan->q_flag & QREADR) != ! 5015: (scan->q_next->q_flag & QREADR)) { ! 5016: /* ! 5017: * Set scan to NULL to flag an unsuccessful ! 5018: * search. ! 5019: */ ! 5020: ! 5021: scan = NULL; ! 5022: break; ! 5023: } ! 5024: ! 5025: scan = scan->q_next; ! 5026: ! 5027: if ((scan->q_flag & QPROCSOFF) != 0) ! 5028: continue; ! 5029: ! 5030: if (scan->q_qinfo == module->mod_stream->st_wrinit) ! 5031: break; ! 5032: } ! 5033: ! 5034: SHEAD_UNLOCK (sheadp, prev_pl); ! 5035: ! 5036: * rvalp = scan != NULL; ! 5037: } ! 5038: ! 5039: return 0; ! 5040: } ! 5041: ! 5042: ! 5043: /* ! 5044: * This function implements the I_LIST ioctl () for the case where the user ! 5045: * supplies a buffer to copy the module/driver names into. ! 5046: */ ! 5047: ! 5048: #if __USE_PROTO__ ! 5049: __LOCAL__ int (SHEAD_LIST) (shead_t * sheadp, struct str_list * slistp, ! 5050: int * rvalp) ! 5051: #else ! 5052: __LOCAL__ int ! 5053: SHEAD_LIST __ARGS ((sheadp, slistp, rvalp)) ! 5054: shead_t * sheadp; ! 5055: struct str_list ! 5056: * slistp; ! 5057: int * rvalp; ! 5058: #endif ! 5059: { ! 5060: queue_t * scan; ! 5061: int modcount; ! 5062: int i; ! 5063: struct str_mlist ! 5064: * buf; ! 5065: struct str_mlist ! 5066: * temp; ! 5067: ! 5068: if (slistp->sl_nmods < 1) ! 5069: return EINVAL; ! 5070: ! 5071: /* ! 5072: * The EAGAIN error documented for I_LIST in streamio (7) is ! 5073: * suggestive of how it is implemented; rather than get involved in ! 5074: * tricky synchronization issues, copy the module names into a kernel ! 5075: * buffer and then copy that to user level. ! 5076: */ ! 5077: ! 5078: modcount = SHEAD_MODCOUNT (sheadp); ! 5079: ! 5080: if (modcount > slistp->sl_nmods) ! 5081: modcount = slistp->sl_nmods; ! 5082: ! 5083: ! 5084: /* ! 5085: * If we were paranoid, we'd user kmem_zalloc () to ensure that the ! 5086: * data we copy to user space contains no sensitive information. As it ! 5087: * happens, because of the fact we user strncpy () to fill the buffer ! 5088: * with data, we are guaranteed that we have overwritten all of the ! 5089: * contents. ! 5090: */ ! 5091: ! 5092: if ((buf = (struct str_mlist *) kmem_alloc (modcount * sizeof (* buf), ! 5093: KM_SLEEP)) == NULL) ! 5094: return EAGAIN; ! 5095: ! 5096: /* ! 5097: * Now fill the buffer in by moving down the stream. We don't worry ! 5098: * about the race between the calculation of the buffer size and the ! 5099: * time we fill it in, because the problem also exists for the user; ! 5100: * in order to know how much space to allocate at user level, some ! 5101: * arrangement must have been made to ensure things are stable. ! 5102: */ ! 5103: ! 5104: i = 0; ! 5105: scan = W (sheadp->sh_head); ! 5106: temp = buf; ! 5107: ! 5108: (void) SHEAD_LOCK (sheadp); ! 5109: ! 5110: while (scan->q_next != NULL && ! 5111: ((scan->q_flag & QREADR) == (scan->q_next->q_flag & QREADR))) { ! 5112: ! 5113: scan = scan->q_next; ! 5114: ! 5115: if ((scan->q_flag & QPROCSOFF) != 0) ! 5116: continue; ! 5117: ! 5118: if (i ++ > modcount) ! 5119: break; ! 5120: ! 5121: /* ! 5122: * Now actually copy the module name. Note that we count on ! 5123: * strncpy () null-padding the target for security. ! 5124: */ ! 5125: ! 5126: strncpy (temp->l_name, scan->q_qinfo->qi_minfo->mi_idname, ! 5127: sizeof (temp->l_name) - 1); ! 5128: temp->l_name [sizeof (temp->l_name) - 1] = 0; ! 5129: } ! 5130: ! 5131: SHEAD_UNLOCK (sheadp, plbase); ! 5132: ! 5133: /* ! 5134: * After unlocking we can safely call copyout (), which we could not ! 5135: * use inside the loop because it may sleep resolving a page fault. ! 5136: * Don't forget that copyout () is like bcopy (), not memcpy ()! ! 5137: */ ! 5138: ! 5139: * rvalp = i; ! 5140: ! 5141: i = copyout (buf, slistp->sl_modlist, i * sizeof (* buf)); ! 5142: ! 5143: kmem_free (buf, modcount * sizeof (* buf)); ! 5144: ! 5145: return i == 0 ? 0 : EFAULT; ! 5146: } ! 5147: ! 5148: ! 5149: /* ! 5150: * This function deals with setting the stream head read mode flag bits in ! 5151: * M_SETOPT messages or from an I_SRDOPT ioctl (). ! 5152: */ ! 5153: ! 5154: #if __USE_PROTO__ ! 5155: int (SHEAD_SRDOPT) (shead_t * sheadp, int flag) ! 5156: #else ! 5157: int ! 5158: SHEAD_SRDOPT __ARGS ((sheadp, flag)) ! 5159: shead_t * sheadp; ! 5160: int flag; ! 5161: #endif ! 5162: { ! 5163: int newflag; ! 5164: ! 5165: SHEAD_ASSERT_LOCKED (sheadp); ! 5166: ! 5167: if ((newflag = flag & RMODEMASK) == __RINVAL) ! 5168: return EINVAL; ! 5169: ! 5170: /* ! 5171: * The streamio (7) man pages seem ambiguous about whether an ! 5172: * application is permitted to, has to, or cannot diagnose a request ! 5173: * to set multiple read options. ! 5174: * ! 5175: * Arbitrarily, we choose not to. ! 5176: */ ! 5177: ! 5178: newflag |= (flag & RPROTNORM) != 0 ? RPROTNORM : ! 5179: (flag & RPROTDAT) != 0 ? RPROTDAT : ! 5180: (flag & RPROTDIS) != 0 ? RPROTDIS : ! 5181: (sheadp->sh_readopt & ~ RMODEMASK); ! 5182: ! 5183: sheadp->sh_readopt = newflag; ! 5184: ! 5185: return 0; ! 5186: } ! 5187: ! 5188: ! 5189: /* ! 5190: * This table determines how many bytes to copy from user space at the start ! 5191: * of ioctl () processing and how many bytes to copy to user space at the end ! 5192: * of processing (presuming no other errors have occurred yet). ! 5193: */ ! 5194: ! 5195: #define BADLEN ((unsigned short) -1) ! 5196: ! 5197: typedef enum { ! 5198: IO_NOLOCK = 0, ! 5199: IO_BASIC_LOCK, ! 5200: IO_READFREEZE, ! 5201: IO_SLEEP_LOCK ! 5202: } iolock_t; ! 5203: ! 5204: enum { NOHUP, ! 5205: HUP ! 5206: }; ! 5207: ! 5208: static struct ioinfo { ! 5209: iolock_t lock; /* lock type */ ! 5210: cat_t cat; /* category flag */ ! 5211: unsigned short in_len; /* bytes to copy in */ ! 5212: unsigned short out_len; /* bytes to copy out */ ! 5213: unsigned char hup_chk; /* check for hangup */ ! 5214: } _ioctl_table [] = { ! 5215: { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP }, ! 5216: /* illegal */ ! 5217: { IO_READFREEZE, SH_NONE, sizeof (size_t), NOHUP }, ! 5218: /* I_NREAD */ ! 5219: { IO_SLEEP_LOCK, SH_OPENCLOSE | SH_IOCTL_LOCK, ! 5220: FMNAMESZ + 1, 0, HUP }, /* I_PUSH */ ! 5221: { IO_SLEEP_LOCK, SH_OPENCLOSE | SH_IOCTL_LOCK, 0, 0, HUP }, ! 5222: /* I_POP */ ! 5223: { IO_NOLOCK, SH_NONE, FMNAMESZ + 1, FMNAMESZ + 1, NOHUP }, ! 5224: /* I_LOOK */ ! 5225: { IO_NOLOCK, SH_NONE, 0, 0, HUP }, /* I_FLUSH */ ! 5226: { IO_BASIC_LOCK, SH_NONE, 0, 0, NOHUP },/* I_SRDOPT */ ! 5227: { IO_BASIC_LOCK, SH_NONE, 0, sizeof (int), NOHUP }, ! 5228: /* I_GRDOPT */ ! 5229: { IO_SLEEP_LOCK, SH_IOCTL_LOCK, sizeof (struct strioctl), ! 5230: sizeof (struct strioctl), HUP },/* I_STR */ ! 5231: { IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, 0, NOHUP }, ! 5232: /* I_SETSIG */ ! 5233: { IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, sizeof (int), NOHUP }, ! 5234: /* I_GETSIG */ ! 5235: { IO_NOLOCK, SH_NONE, FMNAMESZ + 1, 0, NOHUP }, ! 5236: /* I_FIND */ ! 5237: { IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, 0, HUP }, ! 5238: /* I_LINK */ ! 5239: { IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, 0, HUP }, ! 5240: /* I_UNLINK */ ! 5241: { IO_SLEEP_LOCK, SH_READ_LOCK, 0, sizeof (struct strrecvfd), HUP }, ! 5242: /* I_RECVFD */ ! 5243: { IO_SLEEP_LOCK, SH_READ_LOCK, sizeof (struct strpeek), ! 5244: sizeof (struct strpeek), NOHUP },/* I_PEEK */ ! 5245: { IO_NOLOCK, SH_NONE, sizeof (struct strfdinsert), 0, NOHUP }, ! 5246: /* I_FDINSERT */ ! 5247: { IO_NOLOCK, SH_NONE, 0, 0, HUP }, /* I_SENDFD */ ! 5248: { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP }, ! 5249: /* --- */ ! 5250: { IO_BASIC_LOCK, SH_NONE, 0, 0, NOHUP },/* I_SWROPT */ ! 5251: { IO_BASIC_LOCK, SH_NONE, 0, sizeof (int), NOHUP }, ! 5252: /* I_GWROPT */ ! 5253: { IO_NOLOCK, SH_NONE, 0, 0, NOHUP }, /* I_LIST */ /* special */ ! 5254: { IO_BASIC_LOCK, SH_OPENCLOSE | SH_IOCTL_LOCK, 0, 0, HUP }, ! 5255: /* I_PLINK */ ! 5256: { IO_BASIC_LOCK, SH_OPENCLOSE | SH_IOCTL_LOCK, 0, 0, HUP }, ! 5257: /* I_PUNLINK */ ! 5258: { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP }, ! 5259: /* I_SETEV */ ! 5260: { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP }, ! 5261: /* I_GETEV */ ! 5262: { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP }, ! 5263: /* I_STREV */ ! 5264: { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP }, ! 5265: /* I_UNSTREV */ ! 5266: { IO_NOLOCK, SH_NONE, sizeof (struct bandinfo), 0, HUP }, ! 5267: /* I_FLUSHBAND */ ! 5268: { IO_READFREEZE, SH_NONE, 0, 0, NOHUP },/* I_CKBAND */ ! 5269: { IO_READFREEZE, SH_NONE, 0, sizeof (int), NOHUP }, ! 5270: /* I_GETBAND */ ! 5271: { IO_READFREEZE, SH_NONE, 0, 0, NOHUP },/* I_ATMARK */ ! 5272: { IO_BASIC_LOCK, SH_NONE, sizeof (__clock_t), 0, NOHUP }, ! 5273: /* I_SETCLTIME */ ! 5274: { IO_BASIC_LOCK, SH_NONE, 0, sizeof (__clock_t), NOHUP }, ! 5275: /* I_GETCLTIME */ ! 5276: { IO_NOLOCK, SH_NONE, 0, 0, HUP } /* I_CANPUT */ ! 5277: }; ! 5278: ! 5279: struct ioinfo _transparent = { ! 5280: IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, 0, HUP ! 5281: }; ! 5282: ! 5283: ! 5284: /* ! 5285: * Symbol for accessing the default ioctl () and close timeouts. Consider ! 5286: * making this a static variable and initializing it at boot time. ! 5287: */ ! 5288: ! 5289: #define IOCTL_TIMEOUT drv_usectohz ((__clock_t) 15000000L) ! 5290: ! 5291: ! 5292: /* ! 5293: * Main ioctl () processing for STREAMS files and pipes. ! 5294: * ! 5295: * This switch+table is an abomination, but trying to emulate C++ style in C ! 5296: * to subsume the switch and the above table would probably kill me. This ! 5297: * probably is about as short as it can really be. ! 5298: */ ! 5299: ! 5300: #if __USE_PROTO__ ! 5301: int (STREAMS_IOCTL) (shead_t * sheadp, int cmd, _VOID * arg, int mode, ! 5302: cred_t * credp, int * rvalp) ! 5303: #else ! 5304: int ! 5305: STREAMS_IOCTL (sheadp, cmd, arg, mode, credp, rvalp) ! 5306: shead_t * sheadp; ! 5307: int cmd; ! 5308: _VOID * arg; ! 5309: int mode; ! 5310: cred_t * credp; ! 5311: int * rvalp; ! 5312: #endif ! 5313: { ! 5314: union { ! 5315: int i_int; ! 5316: __clock_t i_clock; ! 5317: size_t i_size; ! 5318: char i_modname [FMNAMESZ + 1]; ! 5319: struct strioctl i_strioc; ! 5320: struct strrecvfd i_recvfd; ! 5321: struct strbuf i_strbuf; ! 5322: struct strfdinsert ! 5323: i_fdinsert; ! 5324: struct str_list i_list; ! 5325: struct bandinfo i_band; ! 5326: struct strpeek i_peek; ! 5327: } iocbuf; ! 5328: int retval; ! 5329: struct ioinfo * info; ! 5330: ! 5331: ASSERT (sheadp != NULL); ! 5332: ! 5333: /* ! 5334: * We start out by copying in the data specified by the table, which ! 5335: * means we also get to range-check the ioctl entry if it has the ! 5336: * magic STREAMS id. ! 5337: */ ! 5338: ! 5339: if ((cmd & ~ 0xFF) == STREAM_I) { ! 5340: int index = cmd & 0xFF; ! 5341: ! 5342: if (index >= sizeof (_ioctl_table) / sizeof (* info)) ! 5343: return EINVAL; ! 5344: ! 5345: info = & _ioctl_table [index]; ! 5346: } else ! 5347: info = & _transparent; ! 5348: ! 5349: if (info->in_len == BADLEN) ! 5350: return EINVAL; ! 5351: ! 5352: /* ! 5353: * We *must* do the copy before the lock! Never forget that ! 5354: * copyin ()/copyout () can block in page fault resolution. ! 5355: */ ! 5356: ! 5357: if (info->in_len > 0 && copyin (arg, & iocbuf, info->in_len) != 0) ! 5358: return EFAULT; ! 5359: ! 5360: /* ! 5361: * We may wish to check for a hangup or error before proceeding. ! 5362: */ ! 5363: ! 5364: (void) SHEAD_LOCK (sheadp); ! 5365: ! 5366: if (info->hup_chk == HUP && ! 5367: (retval = SHEAD_ERRHUP_LOCKED (sheadp, mode)) != 0) ! 5368: return ENXIO; ! 5369: ! 5370: if (info->lock != IO_BASIC_LOCK) ! 5371: SHEAD_UNLOCK (sheadp, plbase); ! 5372: ! 5373: switch (info->lock) { ! 5374: ! 5375: case IO_BASIC_LOCK: ! 5376: /* stay holding on to the basic lock */ ! 5377: break; ! 5378: ! 5379: case IO_READFREEZE: ! 5380: (void) QFREEZE_TRACE (sheadp->sh_head, "STREAMS_IOCTL"); ! 5381: break; ! 5382: ! 5383: case IO_SLEEP_LOCK: ! 5384: if ((retval = SHEAD_SLEEP_LOCK (sheadp, info->cat, ! 5385: IOCTL_TIMEOUT, ! 5386: CHECK_SIGNALS)) != 0) ! 5387: return retval; ! 5388: break; ! 5389: ! 5390: default: ! 5391: break; ! 5392: } ! 5393: ! 5394: retval = 0; ! 5395: ! 5396: switch (cmd) { ! 5397: ! 5398: case I_NREAD: /* Get message length, count */ ! 5399: { ! 5400: mblk_t * scan; ! 5401: mblk_t * first = NULL; ! 5402: ! 5403: * rvalp = 0; ! 5404: ! 5405: for (scan = SHEAD_FIRSTMSG (sheadp) ; scan != NULL ; ! 5406: scan = scan->b_next) { ! 5407: ! 5408: if (datamsg (scan->b_datap->db_type)) { ! 5409: ! 5410: if (first == NULL) ! 5411: first = scan; ! 5412: (* rvalp) ++; ! 5413: } ! 5414: } ! 5415: ! 5416: if (first != NULL) ! 5417: iocbuf.i_int = msgdsize (first); ! 5418: else ! 5419: iocbuf.i_int = 0; ! 5420: } ! 5421: break; ! 5422: ! 5423: case I_PUSH: /* push named module */ ! 5424: { ! 5425: modsw_t * module; ! 5426: ! 5427: if ((module = FIND_MODULE (iocbuf.i_modname)) == NULL) ! 5428: retval = EINVAL; ! 5429: else ! 5430: retval = PUSH_MODULE (sheadp, mode, credp, ! 5431: module); ! 5432: } ! 5433: break; ! 5434: ! 5435: case I_POP: /* pop topmost module */ ! 5436: { ! 5437: queue_t * q; ! 5438: ! 5439: if ((q = TOP_MODULE (sheadp)) == NULL) ! 5440: retval = EINVAL; ! 5441: else ! 5442: retval = POP_MODULE (sheadp, q, mode, credp); ! 5443: } ! 5444: break; ! 5445: ! 5446: case I_LOOK: /* get topmost module name */ ! 5447: { ! 5448: queue_t * q; ! 5449: ! 5450: if ((q = TOP_MODULE (sheadp)) == NULL) ! 5451: retval = EINVAL; ! 5452: else { ! 5453: /* ! 5454: * Copy the module name, taking care to ! 5455: * 0-terminate it at FMNAMESZ bytes long. ! 5456: */ ! 5457: ! 5458: strncpy (iocbuf.i_modname, ! 5459: q->q_qinfo->qi_minfo->mi_idname, ! 5460: FMNAMESZ); ! 5461: iocbuf.i_modname [FMNAMESZ] = 0; ! 5462: } ! 5463: } ! 5464: break; ! 5465: ! 5466: case I_FLUSH: /* flush read and/or write side */ ! 5467: retval = SHEAD_FLUSH (sheadp, (int) arg, 0); ! 5468: break; ! 5469: ! 5470: case I_SRDOPT: /* set read options */ ! 5471: retval = SHEAD_SRDOPT (sheadp, (int) arg); ! 5472: break; ! 5473: ! 5474: case I_GRDOPT: /* retrieve read options */ ! 5475: iocbuf.i_int = sheadp->sh_readopt; ! 5476: break; ! 5477: ! 5478: case I_STR: /* send ioctl () data down a stream */ ! 5479: if ((iocbuf.i_strioc.ic_cmd & ~ 0xFF) == STREAM_I || ! 5480: (unsigned) iocbuf.i_strioc.ic_len == TRANSPARENT) { ! 5481: /* ! 5482: * We do not permit I_STR to send STREAMS ioctl () ! 5483: * codes downstream; in certain cases such as I_LINK ! 5484: * this could produce disastrous results. ! 5485: * ! 5486: * We also do not permit TRANSPARENT length I_STR ! 5487: * messages. While the STREAMS documentation neither ! 5488: * explicitly permits or forbids this, we keep the ! 5489: * transparent ioctl () behaviour separate. ! 5490: */ ! 5491: ! 5492: retval = EINVAL; ! 5493: break; ! 5494: ! 5495: } ! 5496: ! 5497: retval = ISTR_IOCTL (sheadp, mode, & iocbuf.i_strioc, credp, ! 5498: rvalp); ! 5499: break; ! 5500: ! 5501: case I_SETSIG: /* register events for SIGPOLL signal */ ! 5502: { ! 5503: int events = (short) (ulong_t) arg; ! 5504: ! 5505: if ((events & ~ __POLL_MASK) != 0) ! 5506: retval = EINVAL; ! 5507: else ! 5508: retval = REGISTER_SIGPOLL (sheadp, events); ! 5509: } ! 5510: break; ! 5511: ! 5512: case I_GETSIG: /* return registered event mask */ ! 5513: { ! 5514: sigpoll_t * sigs; ! 5515: ! 5516: if ((sigs = FIND_SIGPOLL (sheadp)) == NULL) ! 5517: retval = EINVAL; ! 5518: else ! 5519: * rvalp = sigs->sp_events; ! 5520: } ! 5521: break; ! 5522: ! 5523: case I_FIND: /* determine if module exists on stream */ ! 5524: retval = SHEAD_FIND_MODINFO (sheadp, iocbuf.i_modname, rvalp); ! 5525: break; ! 5526: ! 5527: case I_LINK: /* link stream below another */ ! 5528: case I_PLINK: /* create a persistent link */ ! 5529: { ! 5530: shead_t * lower; ! 5531: ! 5532: if ((lower = FH_TO_STREAM ((int) arg, ! 5533: & retval)) != NULL) { ! 5534: retval = SHEAD_LINK (sheadp, mode, lower, cmd, ! 5535: credp); ! 5536: ! 5537: if (retval == 0) ! 5538: * rvalp = lower->sh_muxid; ! 5539: } ! 5540: } ! 5541: break; ! 5542: ! 5543: case I_UNLINK: /* remove a (or all) link(s) below a stream */ ! 5544: case I_PUNLINK: /* undo a single or all persistent link(s) */ ! 5545: do { ! 5546: shead_t * lower; ! 5547: ! 5548: if ((lower = SHEAD_FIND_MUXID (sheadp, cmd, ! 5549: (int) arg)) == NULL) { ! 5550: /* ! 5551: * We return EINVAL if a specific mux ID was ! 5552: * given, 0 otherwise. ! 5553: */ ! 5554: ! 5555: retval = (int) arg == -1 ? 0 : EINVAL; ! 5556: break; ! 5557: ! 5558: } ! 5559: ! 5560: (void) SHEAD_UNLINK (sheadp, lower, cmd, mode, credp, ! 5561: & retval); ! 5562: } while ((int) arg == -1); ! 5563: break; ! 5564: ! 5565: case I_RECVFD: /* receive a file descriptor from stream */ ! 5566: retval = FH_RECV (sheadp, mode, & iocbuf.i_recvfd); ! 5567: break; ! 5568: ! 5569: case I_PEEK: /* examine data at stream head */ ! 5570: retval = SHEAD_PEEK (sheadp, & iocbuf.i_peek, rvalp); ! 5571: break; ! 5572: ! 5573: case I_FDINSERT: /* send read queue pointer down stream */ ! 5574: retval = SHEAD_FDINSERT (sheadp, mode, & iocbuf.i_fdinsert); ! 5575: break; ! 5576: ! 5577: case I_SENDFD: /* send a file descriptor down a pipe */ ! 5578: retval = FH_SEND (sheadp, (int) arg, credp); ! 5579: break; ! 5580: ! 5581: case I_SWROPT: /* set write options for stream */ ! 5582: { ! 5583: int flag = (int) arg; ! 5584: ! 5585: if ((flag & ~ SNDZERO) != 0) ! 5586: retval = EINVAL; ! 5587: else ! 5588: sheadp->sh_wropt = flag; ! 5589: } ! 5590: break; ! 5591: ! 5592: case I_GWROPT: /* retrieve write options for stream */ ! 5593: iocbuf.i_int = sheadp->sh_wropt; ! 5594: break; ! 5595: ! 5596: case I_LIST: /* get names of all modules/drivers */ ! 5597: /* ! 5598: * The value of "arg" is a pointer to a structure for this ! 5599: * entry, but since a NULL value is legal we don't copy the ! 5600: * data in automatically. ! 5601: * ! 5602: * Here we select the call type and copy in the structure for ! 5603: * the non-NULL case. ! 5604: */ ! 5605: ! 5606: if (arg == NULL) ! 5607: * rvalp = SHEAD_MODCOUNT (sheadp); ! 5608: else if (copyin (arg, & iocbuf, sizeof (iocbuf.i_list)) != 0) ! 5609: retval = EFAULT; ! 5610: else ! 5611: retval = SHEAD_LIST (sheadp, & iocbuf.i_list, rvalp); ! 5612: break; ! 5613: ! 5614: case I_SETEV: /* The meaning of these ioctl ()'s is not */ ! 5615: case I_GETEV: /* documented, although their names and */ ! 5616: case I_STREV: /* numeric values are given in the System */ ! 5617: case I_UNSTREV: /* V ABI. */ ! 5618: retval = EINVAL; ! 5619: break; ! 5620: ! 5621: case I_FLUSHBAND: /* flush messages in a priority band */ ! 5622: retval = SHEAD_FLUSH (sheadp, iocbuf.i_band.bi_flag, ! 5623: iocbuf.i_band.bi_pri); ! 5624: break; ! 5625: ! 5626: case I_CKBAND: /* check for existence of band on stream */ ! 5627: if ((uchar_t) (ulong_t) arg != (ulong_t) arg) ! 5628: retval = EINVAL; ! 5629: else { ! 5630: mblk_t * scan; ! 5631: ! 5632: for (scan = SHEAD_FIRSTMSG (sheadp) ; scan != NULL ; ! 5633: scan = scan->b_next) ! 5634: if (datamsg (scan->b_datap->db_type) && ! 5635: scan->b_band == (uchar_t) (ulong_t) arg) ! 5636: break; ! 5637: ! 5638: * rvalp = scan != NULL; ! 5639: } ! 5640: break; ! 5641: ! 5642: case I_GETBAND: /* get the band number of the first message */ ! 5643: { ! 5644: mblk_t * scan; ! 5645: ! 5646: for (scan = SHEAD_FIRSTMSG (sheadp) ; scan != NULL ; ! 5647: scan = scan->b_next) { ! 5648: ! 5649: if (datamsg (scan->b_datap->db_type)) ! 5650: break; ! 5651: } ! 5652: ! 5653: if (scan == NULL) ! 5654: retval = ENODATA; ! 5655: else ! 5656: iocbuf.i_int = scan->b_band; ! 5657: } ! 5658: break; ! 5659: ! 5660: case I_ATMARK: /* test for (last) mark on messages */ ! 5661: { ! 5662: mblk_t * scan = SHEAD_FIRSTMSG (sheadp); ! 5663: ! 5664: if ((ulong_t) arg != ANYMARK && ! 5665: (ulong_t) arg != LASTMARK) { ! 5666: ! 5667: retval = EINVAL; ! 5668: break; ! 5669: } ! 5670: ! 5671: if (scan == NULL || (scan->b_flag & MSGMARK) == 0) { ! 5672: ! 5673: * rvalp = 0; ! 5674: break; ! 5675: } ! 5676: ! 5677: * rvalp = 1; ! 5678: ! 5679: if ((ulong_t) arg == LASTMARK) ! 5680: while ((scan = scan->b_next) != NULL) ! 5681: if ((scan->b_flag & MSGMARK) != 0) { ! 5682: * rvalp = 0; ! 5683: break; ! 5684: } ! 5685: } ! 5686: break; ! 5687: ! 5688: case I_SETCLTIME: /* set close timeout for stream */ ! 5689: if (iocbuf.i_clock != 0) ! 5690: sheadp->sh_cltime = iocbuf.i_clock; ! 5691: else ! 5692: retval = EINVAL; ! 5693: break; ! 5694: ! 5695: case I_GETCLTIME: /* retrieve current close timeout */ ! 5696: iocbuf.i_clock = sheadp->sh_cltime; ! 5697: break; ! 5698: ! 5699: case I_CANPUT: /* test if band is writeable */ ! 5700: if ((uchar_t) (ulong_t) arg != (ulong_t) arg) ! 5701: retval = EINVAL; ! 5702: else ! 5703: * rvalp = bcanputnext (W (sheadp->sh_head), ! 5704: (uchar_t) (ulong_t) arg); ! 5705: break; ! 5706: ! 5707: default: ! 5708: ASSERT (info == & _transparent); ! 5709: ! 5710: retval = TRANSPARENT_IOCTL (sheadp, mode, cmd, arg, credp, ! 5711: rvalp); ! 5712: break; ! 5713: } ! 5714: ! 5715: ! 5716: /* ! 5717: * Perform any necessary unlocking operations and copy back any ! 5718: * results into the data area pointed to by "arg" (if this is a ! 5719: * STREAMS-specific ioctl ()). ! 5720: */ ! 5721: ! 5722: switch (info->lock) { ! 5723: ! 5724: case IO_BASIC_LOCK: ! 5725: SHEAD_UNLOCK (sheadp, plbase); ! 5726: break; ! 5727: ! 5728: case IO_READFREEZE: ! 5729: (void) QUNFREEZE_TRACE (sheadp->sh_head, plbase); ! 5730: break; ! 5731: ! 5732: case IO_SLEEP_LOCK: ! 5733: SHEAD_SLEEP_UNLOCK (sheadp, info->cat); ! 5734: break; ! 5735: ! 5736: default: ! 5737: break; ! 5738: } ! 5739: ! 5740: ! 5741: /* ! 5742: * We only copy out results if there is no error. We have to ! 5743: * do this *after* unlocking, above; copyout () can block in ! 5744: * page fault resolution! ! 5745: */ ! 5746: ! 5747: if (retval == 0 && info->out_len > 0 && ! 5748: copyout (& iocbuf, arg, info->out_len) != 0) ! 5749: retval = EFAULT; ! 5750: ! 5751: return retval; ! 5752: } ! 5753: ! 5754: ! 5755: /* ! 5756: * Helper function to atomically read the stream head read options. ! 5757: */ ! 5758: ! 5759: #if __USE_PROTO__ ! 5760: __LOCAL__ short (SHEAD_READOPT) (shead_t * sheadp) ! 5761: #else ! 5762: __LOCAL__ short ! 5763: SHEAD_READOPT __ARGS ((sheadp)) ! 5764: shead_t * sheadp; ! 5765: #endif ! 5766: { ! 5767: pl_t prev_pl; ! 5768: short opt; ! 5769: ! 5770: prev_pl = SHEAD_LOCK (sheadp); ! 5771: ! 5772: opt = sheadp->sh_readopt; ! 5773: ! 5774: SHEAD_UNLOCK (sheadp, prev_pl); ! 5775: ! 5776: return opt; ! 5777: } ! 5778: ! 5779: ! 5780: /* ! 5781: * Stream head user-level getmsg () processing. ! 5782: * ! 5783: * This is way too many parameters; this should be bundled into a block like ! 5784: * the "uio" structure is. ! 5785: */ ! 5786: ! 5787: #if __USE_PROTO__ ! 5788: int (STREAMS_GETPMSG) (shead_t * sheadp, struct strbuf * ctlbuf, ! 5789: struct strbuf * databuf, int * bandp, int * flagsp, ! 5790: int mode, int * rvalp) ! 5791: #else ! 5792: int ! 5793: STREAMS_GETPMSG __ARGS ((sheadp, ctlbuf, databuf, bandp, flagsp, mode, rvalp)) ! 5794: shead_t * sheadp; ! 5795: int mode; ! 5796: struct strbuf * ctlbuf; ! 5797: struct strbuf * databuf; ! 5798: int * bandp; ! 5799: int * flagsp; ! 5800: int * rvalp; ! 5801: #endif ! 5802: { ! 5803: mblk_t * msg; ! 5804: mblk_t * scan; ! 5805: int retval; ! 5806: ! 5807: if ((mode & FREAD) == 0) ! 5808: return EBADF; ! 5809: ! 5810: mode &= ~ FWRITE; ! 5811: ! 5812: ! 5813: /* ! 5814: * As discussed in the general comment on read synchronization and in ! 5815: * the I_PEEK documentation, there are some warts when it comes to ! 5816: * read locking. Here we can solve things by dequeueing a message, ! 5817: * modifying at, and writing it back without worrying about any nasty ! 5818: * unintended effects. ! 5819: * ! 5820: * Because getmsg ()/getpmsg () always honours message boundaries, ! 5821: * there is no real value in single-threading this. ! 5822: */ ! 5823: ! 5824: /* ! 5825: * Look at the stream head to see if a message is present. Note that ! 5826: * we freeze the read queue before acquiring the stream head basic ! 5827: * lock because that's our canonical ordering. ! 5828: */ ! 5829: ! 5830: for (;;) { ! 5831: (void) QFREEZE_TRACE (sheadp->sh_head, "SHEAD_GETPMSG"); ! 5832: ! 5833: (void) SHEAD_LOCK (sheadp); ! 5834: ! 5835: if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, FREAD)) != 0) { ! 5836: ! 5837: QUNFREEZE_TRACE (sheadp->sh_head, plbase); ! 5838: return retval; ! 5839: } ! 5840: ! 5841: ! 5842: if ((msg = SHEAD_FIRSTMSG (sheadp)) != NULL) { ! 5843: ! 5844: switch (msg->b_datap->db_type) { ! 5845: ! 5846: case M_DATA: ! 5847: case M_PROTO: ! 5848: ! 5849: if (* flagsp == MSG_HIPRI || ! 5850: (* flagsp == MSG_BAND && ! 5851: msg->b_band < * bandp)) { ! 5852: ! 5853: sheadp->sh_head->q_lastband = ! 5854: msg->b_band; ! 5855: msg = NULL; ! 5856: break; ! 5857: } ! 5858: ! 5859: /* FALL THROUGH */ ! 5860: ! 5861: case M_PCPROTO: ! 5862: rmvq (sheadp->sh_head, msg); ! 5863: break; ! 5864: ! 5865: default: ! 5866: retval = EBADMSG; ! 5867: break; ! 5868: } ! 5869: } ! 5870: ! 5871: QUNFREEZE_TRACE (sheadp->sh_head, plbase); ! 5872: ! 5873: if (retval != 0) ! 5874: return retval; ! 5875: ! 5876: if (msg != NULL) ! 5877: break; ! 5878: ! 5879: /* ! 5880: * We need to wait (unless O_NDELAY or O_NONBLOCK has been ! 5881: * specified). We don't wait any more if the stream has been ! 5882: * hung up. ! 5883: */ ! 5884: ! 5885: if (SHEAD_HANGUP (sheadp)) { ! 5886: /* ! 5887: * Hangups are not an error for getpmsg (). ! 5888: */ ! 5889: ! 5890: if (ctlbuf != NULL) ! 5891: ctlbuf->len = 0; ! 5892: if (databuf != NULL) ! 5893: databuf->len = 0; ! 5894: ! 5895: * rvalp = 0; ! 5896: return 0; ! 5897: } ! 5898: ! 5899: if ((retval = SHEAD_WAIT_NONBLOCK (sheadp, FREAD, ! 5900: SH_READ_WAIT, ! 5901: CHECK_SIGNALS)) != 0) ! 5902: return retval; ! 5903: } ! 5904: ! 5905: ! 5906: /* ! 5907: * After this point, "msg" is our responsibility and we either have to ! 5908: * free it or put it back if there is an error. ! 5909: */ ! 5910: ! 5911: * bandp = msg->b_band; ! 5912: * flagsp = msg->b_datap->db_type == M_PCPROTO ? MSG_HIPRI : MSG_BAND; ! 5913: ! 5914: retval = (COPYOUT_BUF (ctlbuf, & msg, CONTROL_PART) != 0 || ! 5915: COPYOUT_BUF (databuf, & msg, ! 5916: DATA_PART) != 0) ? EFAULT : 0; ! 5917: ! 5918: /* ! 5919: * Formulate a return mask indicating what components of the message ! 5920: * being transferred have not been fully consumed. ! 5921: */ ! 5922: ! 5923: * rvalp = 0; ! 5924: ! 5925: for (scan = msg ; scan != NULL ; scan = scan->b_cont) ! 5926: * rvalp |= scan->b_datap->db_type == M_DATA ? MOREDATA ! 5927: : MORECTL; ! 5928: ! 5929: if (msg != NULL) ! 5930: putbq (sheadp->sh_head, msg); ! 5931: ! 5932: return retval; ! 5933: } ! 5934: ! 5935: ! 5936: /* ! 5937: * In order to keep the logic of SHEAD_READ () manageable, this section of ! 5938: * code has been factored into a separate function. Here we wait for data to ! 5939: * become available at the stream head for reading. ! 5940: * ! 5941: * We return 0 on success, or an error number on failure. The value of "mpp" ! 5942: * is only valid if 0 is returned. ! 5943: */ ! 5944: ! 5945: #if __USE_PROTO__ ! 5946: __LOCAL__ int (SHEAD_READ_DATA) (shead_t * sheadp, int mode, mblk_t ** mpp, ! 5947: int resid) ! 5948: #else ! 5949: __LOCAL__ int ! 5950: SHEAD_READ_DATA __ARGS ((sheadp, mode, mpp, resid)) ! 5951: shead_t * sheadp; ! 5952: int mode; ! 5953: mblk_t ** mpp; ! 5954: int resid; ! 5955: #endif ! 5956: { ! 5957: int retval; ! 5958: ! 5959: for (;;) { ! 5960: (void) QFREEZE_TRACE (sheadp->sh_head, "SHEAD_READ"); ! 5961: ! 5962: (void) SHEAD_LOCK (sheadp); ! 5963: ! 5964: if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, FREAD)) != 0) { ! 5965: ! 5966: QUNFREEZE_TRACE (sheadp->sh_head, plbase); ! 5967: return retval; ! 5968: } ! 5969: ! 5970: ! 5971: if ((* mpp = SHEAD_FIRSTMSG (sheadp)) != NULL) { ! 5972: ! 5973: switch ((* mpp)->b_datap->db_type) { ! 5974: ! 5975: case M_PROTO: ! 5976: case M_PCPROTO: ! 5977: /* ! 5978: * These are valid depending on the read mode ! 5979: * of the stream. ! 5980: */ ! 5981: ! 5982: if ((sheadp->sh_readopt & RPROTNORM) != 0) { ! 5983: ! 5984: retval = EBADMSG; ! 5985: break; ! 5986: } ! 5987: ! 5988: /* FALL THROUGH */ ! 5989: ! 5990: case M_DATA: ! 5991: rmvq (sheadp->sh_head, * mpp); ! 5992: break; ! 5993: ! 5994: default: ! 5995: retval = EBADMSG; ! 5996: break; ! 5997: } ! 5998: } ! 5999: ! 6000: QUNFREEZE_TRACE (sheadp->sh_head, plbase); ! 6001: ! 6002: if (retval != 0 || * mpp != NULL) { ! 6003: ! 6004: SHEAD_UNLOCK (sheadp, plbase); ! 6005: return retval; ! 6006: } ! 6007: ! 6008: ! 6009: /* ! 6010: * Since we are going to sleep on a read (), this is the place ! 6011: * to generate M_READ messages if that is how this stream has ! 6012: * been configured. ! 6013: * ! 6014: * If we can't generate an M_READ message, schedule a bufcall. ! 6015: * If we can't do that, return EAGAIN??? ! 6016: */ ! 6017: ! 6018: if (SHEAD_READMSG (sheadp)) { ! 6019: mblk_t * msg; ! 6020: ! 6021: if ((msg = MSGB_ALLOC (sizeof (int), BPRI_LO, ! 6022: KM_NOSLEEP)) == NULL) { ! 6023: /* ! 6024: * Execute a short wait for buffer memory for ! 6025: * the M_READ, then retry the loop. Note that ! 6026: * SHEAD_READ_BUFCALL () unlocks the stream ! 6027: * head for us. ! 6028: */ ! 6029: ! 6030: if ((retval = SHEAD_READ_BUFCALL (sheadp, ! 6031: mode)) != 0) ! 6032: return retval; ! 6033: ! 6034: continue; ! 6035: } ! 6036: ! 6037: msg->b_datap->db_type = M_READ; ! 6038: * (int *) msg->b_rptr = resid; ! 6039: msg->b_wptr += sizeof (int); ! 6040: ! 6041: putq (W (sheadp->sh_head), msg); ! 6042: } ! 6043: ! 6044: if ((retval = SHEAD_WAIT_NONBLOCK (sheadp, mode, SH_READ_WAIT, ! 6045: CHECK_SIGNALS)) != 0) ! 6046: return retval; ! 6047: } ! 6048: ! 6049: } ! 6050: ! 6051: ! 6052: /* ! 6053: * In order to keep the logic of SHEAD_READ () manageable, this section of ! 6054: * code has been factored into this routine, which manages the transfer of ! 6055: * message data to the user. ! 6056: * ! 6057: * We return EAGAIN to the user if more data needs to be read, 0 if the read ! 6058: * has successfully completed, or some other error number on failure. ! 6059: */ ! 6060: ! 6061: #if __USE_PROTO__ ! 6062: __LOCAL__ int (SHEAD_READ_MOVE) (shead_t * sheadp, uio_t * uiop, ! 6063: mblk_t * msg) ! 6064: #else ! 6065: __LOCAL__ int ! 6066: SHEAD_READ_MOVE __ARGS ((sheadp, uiop, msg)) ! 6067: shead_t * sheadp; ! 6068: uio_t * uiop; ! 6069: mblk_t * msg; ! 6070: #endif ! 6071: { ! 6072: int readopt = SHEAD_READOPT (sheadp); ! 6073: mblk_t * scan; ! 6074: ! 6075: if ((readopt & RMODEMASK) == RNORM && ! 6076: (msg->b_cont == NULL && msg->b_rptr == msg->b_wptr)) { ! 6077: /* ! 6078: * We have run into a zero-length message. Put it ! 6079: * back and terminate the read. ! 6080: */ ! 6081: ! 6082: putbq (sheadp->sh_head, msg); ! 6083: return 0; ! 6084: } ! 6085: ! 6086: if ((readopt & RPROTDIS) != 0) { ! 6087: ! 6088: while (msg != NULL && msg->b_datap->db_type != M_DATA) { ! 6089: /* ! 6090: * Consume the control part of the message. ! 6091: */ ! 6092: ! 6093: scan = msg->b_cont; ! 6094: freeb (msg); ! 6095: msg = scan; ! 6096: } ! 6097: ! 6098: if (msg == NULL) ! 6099: return EAGAIN; ! 6100: } ! 6101: ! 6102: ! 6103: /* ! 6104: * Actual data transfer time; copy each message segment to the user ! 6105: * with uiomove (). ! 6106: */ ! 6107: ! 6108: do { ! 6109: size_t unit = msg->b_wptr - msg->b_rptr; ! 6110: ! 6111: if (unit > uiop->uio_resid) ! 6112: unit = uiop->uio_resid; ! 6113: ! 6114: if (unit > 0 && ! 6115: uiomove (msg->b_rptr, unit, UIO_READ, uiop) != 0) { ! 6116: /* ! 6117: * Address fault time. But first, put back the data. ! 6118: */ ! 6119: ! 6120: putbq (sheadp->sh_head, msg); ! 6121: ! 6122: return EFAULT; ! 6123: } ! 6124: ! 6125: msg->b_rptr += unit; ! 6126: ! 6127: if (msg->b_wptr != msg->b_rptr) { ! 6128: /* ! 6129: * Since we didn't finish this message block, we must ! 6130: * be finished with the read (). If we are in message- ! 6131: * discard mode we throw away the remaining data. ! 6132: */ ! 6133: ! 6134: ASSERT (uiop->uio_resid == 0); ! 6135: ! 6136: if ((readopt & RMODEMASK) == RMSGD) ! 6137: freemsg (msg); ! 6138: else ! 6139: putbq (sheadp->sh_head, msg); ! 6140: ! 6141: return 0; ! 6142: } ! 6143: ! 6144: scan = msg->b_cont; ! 6145: freeb (msg); ! 6146: } while ((msg = scan) != NULL); ! 6147: ! 6148: ! 6149: /* ! 6150: * We have run out of message; what now? If in byte-stream mode, look ! 6151: * for more data, otherwise exit. ! 6152: */ ! 6153: ! 6154: return (readopt & RMODEMASK) == RNORM ? EAGAIN : 0; ! 6155: } ! 6156: ! 6157: ! 6158: /* ! 6159: * Stream head user-level read processing. ! 6160: * ! 6161: * I apologise for the abysmal structure of this code; the gotos should be ! 6162: * replaced by proper loops and the major subsections factored into auxiliary ! 6163: * functions, but this code is the victim of time pressure and several ! 6164: * rewrites. By all means encourage the author to improve this in case he has ! 6165: * forgotten to come back and fix it. ! 6166: */ ! 6167: ! 6168: #if __USE_PROTO__ ! 6169: int (STREAMS_READ) (shead_t * sheadp, uio_t * uiop) ! 6170: #else ! 6171: int ! 6172: STREAMS_READ __ARGS ((sheadp, uiop)) ! 6173: shead_t * sheadp; ! 6174: uio_t * uiop; ! 6175: #endif ! 6176: { ! 6177: mblk_t * msg; ! 6178: int retval; ! 6179: int mode; ! 6180: int readcount = uiop->uio_resid; ! 6181: ! 6182: if ((uiop->uio_fmode & FREAD) == 0) ! 6183: return EBADF; ! 6184: ! 6185: mode = uiop->uio_fmode & ~ FWRITE; ! 6186: ! 6187: ! 6188: /* ! 6189: * We (optionally) take out a lock on the stream head to single-thread ! 6190: * reads. This is important because in byte-stream mode we may want ! 6191: * to guarantee atomicity of reads. This is only relevant to byte- ! 6192: * stream mode because modes which honor message boundaries cannot ! 6193: * be protected against multiple readers anyway. ! 6194: */ ! 6195: ! 6196: if ((retval = SHEAD_SLEEP_LOCK (sheadp, SH_READ_LOCK, 0, ! 6197: CHECK_SIGNALS)) != 0) ! 6198: return retval; ! 6199: ! 6200: do { ! 6201: if ((retval = SHEAD_READ_DATA (sheadp, mode, & msg, ! 6202: uiop->uio_resid)) != 0) ! 6203: break; ! 6204: ! 6205: /* ! 6206: * After this point, "msg" is our responsibility and we either ! 6207: * have to free it or put it back if there is an error. ! 6208: */ ! 6209: ! 6210: } while ((retval = SHEAD_READ_MOVE (sheadp, uiop, msg)) == EAGAIN); ! 6211: ! 6212: ! 6213: /* ! 6214: * If a partial read has been done, we return a short read rather than ! 6215: * reporting an error immediately. ! 6216: */ ! 6217: ! 6218: if (retval != 0 && readcount != uiop->uio_resid) ! 6219: retval = 0; ! 6220: ! 6221: SHEAD_SLEEP_UNLOCK (sheadp, SH_READ_LOCK); ! 6222: return retval; ! 6223: } ! 6224: ! 6225: ! 6226: /* ! 6227: * Helper function to atomically read the stream head write options. ! 6228: */ ! 6229: ! 6230: #if __USE_PROTO__ ! 6231: __LOCAL__ short (SHEAD_WRITEOPT) (shead_t * sheadp) ! 6232: #else ! 6233: __LOCAL__ short ! 6234: SHEAD_WRITEOPT __ARGS ((sheadp)) ! 6235: shead_t * sheadp; ! 6236: #endif ! 6237: { ! 6238: pl_t prev_pl; ! 6239: short opt; ! 6240: ! 6241: prev_pl = SHEAD_LOCK (sheadp); ! 6242: ! 6243: opt = sheadp->sh_wropt; ! 6244: ! 6245: SHEAD_UNLOCK (sheadp, prev_pl); ! 6246: ! 6247: return opt; ! 6248: } ! 6249: ! 6250: ! 6251: /* ! 6252: * Stream head user level putpmsg () processing. As with getmsg (), there are ! 6253: * enough parameters being passed that this should be abstracted into a ! 6254: * structure like uio(D4DK). ! 6255: */ ! 6256: ! 6257: #if __USE_PROTO__ ! 6258: int (STREAMS_PUTPMSG) (shead_t * sheadp, struct strbuf * ctlbuf, ! 6259: struct strbuf * databuf, int band, int flags, ! 6260: int mode, int * rvalp) ! 6261: #else ! 6262: int ! 6263: STREAMS_PUTPMSG __ARGS ((sheadp, ctlbuf, databuf, band, flags, mode, rvalp)) ! 6264: shead_t * sheadp; ! 6265: int mode; ! 6266: struct strbuf * ctlbuf; ! 6267: struct strbuf * databuf; ! 6268: int band; ! 6269: int flags; ! 6270: int * rvalp; ! 6271: #endif ! 6272: { ! 6273: mblk_t * msg; ! 6274: int retval; ! 6275: ! 6276: /* ! 6277: * Make a message (possibly high-priority). This can fail if the ! 6278: * requested message is too large for the advertised limits set by the ! 6279: * next thing downstream. SHEAD_MAKEMSG () also checks for error and ! 6280: * hangup conditions, FNDELAY/FNONBLOCK, and flow control. ! 6281: */ ! 6282: ! 6283: msg = SHEAD_MAKEMSG (sheadp, mode, ctlbuf, databuf, flags, band, ! 6284: & retval); ! 6285: ! 6286: if (msg == NULL) ! 6287: return retval; ! 6288: ! 6289: /* ! 6290: * Note that we don't recheck for hangups even though we could have ! 6291: * waited a poentially long time in SHEAD_MAKEMSG (). The hangup ! 6292: * condition has plenty of slop in it with the time it takes write ! 6293: * messages to move down the queue anyway; drivers and modules have to ! 6294: * be able to cope. ! 6295: */ ! 6296: ! 6297: putq (W (sheadp->sh_head), msg); ! 6298: ! 6299: * rvalp = 0; ! 6300: return 0; ! 6301: } ! 6302: ! 6303: ! 6304: /* ! 6305: * Stream head user-level write processing. ! 6306: * ! 6307: * I apologise for the abysmal structure of this code; the gotos should be ! 6308: * replaced by proper loops and the major subsections factored into auxiliary ! 6309: * functions, but this code is the victim of time pressure and several ! 6310: * rewrites. By all means encourage the author to improve this in case he has ! 6311: * forgotten to come back and fix it. ! 6312: */ ! 6313: ! 6314: #if __USE_PROTO__ ! 6315: int (STREAMS_WRITE) (shead_t * sheadp, uio_t * uiop) ! 6316: #else ! 6317: int ! 6318: STREAMS_WRITE __ARGS ((sheadp, uiop)) ! 6319: shead_t * sheadp; ! 6320: uio_t * uiop; ! 6321: #endif ! 6322: { ! 6323: queue_t * q; ! 6324: short wropt = SHEAD_WRITEOPT (sheadp); ! 6325: mblk_t * datamsg; ! 6326: int datasize; ! 6327: int wroff; ! 6328: int retval; ! 6329: int mode; ! 6330: int writecount; ! 6331: ! 6332: if ((uiop->uio_fmode & FWRITE) == 0) ! 6333: return EBADF; ! 6334: ! 6335: mode = uiop->uio_fmode & ~ FREAD; ! 6336: ! 6337: ! 6338: /* ! 6339: * Deal with the zero-length-message special case. ! 6340: */ ! 6341: ! 6342: if ((writecount = uiop->uio_resid) == 0 && (wropt & SNDZERO) == 0) ! 6343: return 0; ! 6344: ! 6345: /* ! 6346: * Unlike putmsg ()/putpmsg (), write () can potentially spread the ! 6347: * data it writes over multiple messages and take a considerable time ! 6348: * to do it, we allow for the possibility of locking the stream head ! 6349: * so that only one write () is in progress at any time. ! 6350: * ! 6351: * The primary purpose of this is to allow PIPE_BUF to be effectively ! 6352: * unlimited. This is an experimental idea, though. ! 6353: */ ! 6354: ! 6355: if ((retval = SHEAD_SLEEP_LOCK (sheadp, SH_WRITE_LOCK, 0, ! 6356: CHECK_SIGNALS)) != 0) ! 6357: return retval; ! 6358: ! 6359: wroff = SHEAD_WRITEOFFSET (sheadp); ! 6360: ! 6361: q = TOP_QUEUE (sheadp); ! 6362: ! 6363: do { ! 6364: ! 6365: if ((datasize = uiop->uio_resid) + wroff > q->q_maxpsz) { ! 6366: /* ! 6367: * Special case (documented on the write (2) manual ! 6368: * page; if we can't fit within the max/min range and ! 6369: * the minimum is greater than 0, return ERANGE. ! 6370: */ ! 6371: ! 6372: if (q->q_minpsz > 0) { ! 6373: ! 6374: retval = ERANGE; ! 6375: break; ! 6376: } ! 6377: ! 6378: datasize = q->q_maxpsz - wroff; ! 6379: } else if (datasize + wroff < q->q_minpsz) { ! 6380: ! 6381: retval = ERANGE; ! 6382: break; ! 6383: } ! 6384: ! 6385: ! 6386: /* ! 6387: * Let's see if the stream is flow controlled; if it is, we ! 6388: * either block or return EAGAIN depending on the ! 6389: * FNDELAY/FNONBLOCK setting. ! 6390: */ ! 6391: ! 6392: if ((retval = SHEAD_WRITE_TEST (sheadp, mode, 0, 0)) != 0) ! 6393: break; ! 6394: ! 6395: if ((datamsg = MSGB_ALLOC (datasize + wroff, BPRI_LO, ! 6396: KM_SLEEP)) == NULL) { ! 6397: retval = ENOSR; ! 6398: break; ! 6399: } ! 6400: ! 6401: datamsg->b_wptr = datamsg->b_rptr = datamsg->b_rptr + wroff; ! 6402: ! 6403: if (datasize > 0 && ! 6404: uiomove (datamsg->b_rptr, datasize, UIO_WRITE, ! 6405: uiop) != 0) { ! 6406: ! 6407: freemsg (datamsg); ! 6408: ! 6409: retval = EFAULT; ! 6410: break; ! 6411: } ! 6412: ! 6413: datamsg->b_wptr += datasize; ! 6414: ! 6415: /* ! 6416: * Now do the write, and see if there is more data. ! 6417: */ ! 6418: ! 6419: putq (W (sheadp->sh_head), datamsg); ! 6420: ! 6421: } while (uiop->uio_resid > 0); ! 6422: ! 6423: ! 6424: /* ! 6425: * If there has been an error after some data was actually written ! 6426: * we return a short read rather than report the error immediately. ! 6427: */ ! 6428: ! 6429: if (retval != 0 && uiop->uio_resid != writecount) ! 6430: retval = 0; ! 6431: ! 6432: SHEAD_SLEEP_UNLOCK (sheadp, SH_WRITE_LOCK); ! 6433: return retval; ! 6434: } ! 6435: ! 6436: ! 6437: /* ! 6438: * Stream head user-level open processing. ! 6439: */ ! 6440: ! 6441: extern struct streamtab headinfo; ! 6442: ! 6443: #if __USE_PROTO__ ! 6444: int (STREAMS_OPEN) (n_dev_t * devp, struct streamtab * stabp, int mode, ! 6445: cred_t * credp) ! 6446: #else ! 6447: int ! 6448: STREAMS_OPEN (devp, stabp, mode, credp) ! 6449: n_dev_t * devp; ! 6450: struct streamtab ! 6451: * stabp; ! 6452: int mode; ! 6453: cred_t * credp; ! 6454: #endif ! 6455: { ! 6456: shead_t * sheadp; ! 6457: queue_t * q; ! 6458: int retval; ! 6459: n_dev_t dev; ! 6460: ! 6461: ASSERT (devp != NULL); ! 6462: ASSERT (stabp != NULL); ! 6463: ASSERT (credp != NULL); ! 6464: ! 6465: ! 6466: dev = * devp; ! 6467: ! 6468: if ((sheadp = SHEAD_OPEN_LOCK (* devp, stabp, & retval)) == NULL) ! 6469: return retval; ! 6470: ! 6471: /* ! 6472: * If this is the first open of the stream, set up the stream head ! 6473: * entry points and the driver entry points. ! 6474: */ ! 6475: ! 6476: q = W (sheadp->sh_head)->q_next; ! 6477: ! 6478: if (sheadp->sh_open_count == 0) { ! 6479: ! 6480: QUEUE_INIT (sheadp->sh_head, & headinfo, QI_NORMAL); ! 6481: qprocson (sheadp->sh_head); ! 6482: ! 6483: QUEUE_INIT (R (q), stabp, QI_NORMAL); ! 6484: } ! 6485: ! 6486: ! 6487: /* ! 6488: * Now we have a stream head (locked, no less), we can call the open ! 6489: * entry points of all the modules and the driver. In the special case ! 6490: * where the open count of the entry is 0, we allow the driver to ! 6491: * change the "dev_t" value to a previously unused number. ! 6492: */ ! 6493: ! 6494: do { ! 6495: retval = (* R (q)->q_qinfo->qi_qopen) ! 6496: (R (q), & dev, mode, ! 6497: q->q_next == NULL ? 0 : MODOPEN, credp); ! 6498: ! 6499: if (dev != * devp && q->q_next != NULL) { ! 6500: /* ! 6501: * A module has changed the device number that we ! 6502: * passed a pointer to. This is not valid! ! 6503: */ ! 6504: ! 6505: cmn_err (CE_WARN, "Module \"%s\" changed its device number", ! 6506: q->q_qinfo->qi_minfo->mi_idname); ! 6507: retval = ENXIO; ! 6508: } ! 6509: ! 6510: if (retval != 0) ! 6511: goto failure; ! 6512: } while ((q = q->q_next) != NULL); ! 6513: ! 6514: ! 6515: /* ! 6516: * The modules and driver have all OK'ed the open, so increment the ! 6517: * open count. Here we also check for the clone case. ! 6518: * ! 6519: * If we want to detect an error after this point, we should execute ! 6520: * a close. ! 6521: */ ! 6522: ! 6523: sheadp->sh_open_count ++; ! 6524: ! 6525: if (dev != * devp) { ! 6526: /* ! 6527: * The driver has requested that the device number of the ! 6528: * queue be assigned differently than the initial device ! 6529: * number. This is only really valid if this is the first open ! 6530: * of the given queue. ! 6531: */ ! 6532: ! 6533: if (sheadp->sh_open_count > 1) { ! 6534: ! 6535: cmn_err (CE_WARN, "Driver \"%s\" changed its device number after inital open", ! 6536: q->q_qinfo->qi_minfo->mi_idname); ! 6537: ! 6538: sheadp->sh_open_count --; ! 6539: ! 6540: retval = ENXIO; ! 6541: goto failure; ! 6542: } ! 6543: ! 6544: ! 6545: /* ! 6546: * Other open attempts may be waiting on the stream head for ! 6547: * the original device number; they need a wakeup. ! 6548: */ ! 6549: ! 6550: if (SHEAD_RENAME (sheadp, dev) != 0) { ! 6551: ! 6552: cmn_err (CE_WARN, "Clone device number chosen by driver \"%s\"is in use", ! 6553: q->q_qinfo->qi_minfo->mi_idname); ! 6554: ! 6555: if (-- sheadp->sh_open_count == 0) ! 6556: SHEAD_DO_CLOSE (sheadp, mode, credp); ! 6557: ! 6558: retval = ENXIO; ! 6559: goto failure; ! 6560: } ! 6561: ! 6562: * devp = dev; ! 6563: } ! 6564: ! 6565: failure: ! 6566: /* ! 6567: * The module or driver has failed the open request. We unlock the ! 6568: * stream head, which may deallocate the stream head if the open count ! 6569: * is 0. ! 6570: */ ! 6571: ! 6572: SHEAD_SLEEP_UNLOCK (sheadp, SH_OPENCLOSE); ! 6573: return retval; ! 6574: } ! 6575: ! 6576: ! 6577: /* ! 6578: * Stream head interface to generic polling. ! 6579: */ ! 6580: ! 6581: #if __USE_PROTO__ ! 6582: int (STREAMS_CHPOLL) (shead_t * sheadp, short events, int anyyet, ! 6583: short * reventsp, struct pollhead ** phpp) ! 6584: #else ! 6585: int ! 6586: STREAMS_CHPOLL __ARGS ((sheadp, events, anyyet, reventsp, phpp)) ! 6587: shead_t * sheadp; ! 6588: short events; ! 6589: int anyyet; ! 6590: short * reventsp; ! 6591: struct pollhead ! 6592: ** phpp; ! 6593: #endif ! 6594: { ! 6595: short my_events; ! 6596: ! 6597: /* ! 6598: * The chpoll () entry point uses the POLL... constants rather than ! 6599: * the S_... constants that I_SETSIG uses. We convert to the S_... ! 6600: * form for our internal use... see <sys/poll.h> ! 6601: */ ! 6602: ! 6603: my_events = (events & (__POLL_INPUT | __POLL_HIPRI | __POLL_OUTPUT | ! 6604: __POLL_RDNORM | __POLL_OUTPUT | ! 6605: __POLL_RDBAND | __POLL_WRBAND)); ! 6606: ! 6607: if ((events & POLLERR) != 0) ! 6608: my_events = S_ERROR; ! 6609: if ((events & POLLHUP) != 0) ! 6610: my_events = S_HANGUP; ! 6611: ! 6612: if ((my_events = SHEAD_POLL_CHECK (sheadp, my_events)) == 0) { ! 6613: ! 6614: * reventsp = 0; ! 6615: ! 6616: if (anyyet == 0) ! 6617: * phpp = sheadp->sh_pollhead; ! 6618: } else ! 6619: * reventsp = my_events; ! 6620: ! 6621: return 0; ! 6622: } ! 6623: ! 6624: ! 6625: /* ! 6626: * Stream head user-level close processing. ! 6627: */ ! 6628: ! 6629: #if __USE_PROTO__ ! 6630: int (STREAMS_CLOSE) (shead_t * sheadp, int mode, cred_t * credp) ! 6631: #else ! 6632: int ! 6633: STREAMS_CLOSE __ARGS ((sheadp, mode, credp)) ! 6634: shead_t * sheadp; ! 6635: int mode; ! 6636: cred_t * credp; ! 6637: #endif ! 6638: { ! 6639: int retval; ! 6640: ! 6641: if ((retval = SHEAD_SLEEP_LOCK (sheadp, SH_OPENCLOSE | SH_IOCTL_LOCK, ! 6642: 0, CHECK_SIGNALS)) != 0) ! 6643: return retval; ! 6644: ! 6645: if (-- sheadp->sh_open_count == 0) ! 6646: SHEAD_DO_CLOSE (sheadp, mode, credp); ! 6647: ! 6648: SHEAD_SLEEP_UNLOCK (sheadp, SH_OPENCLOSE | SH_IOCTL_LOCK); ! 6649: ! 6650: return 0; ! 6651: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.