Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/bufmod.c
+++ new/usr/src/uts/common/io/bufmod.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 27 /*
30 28 * STREAMS Buffering module
31 29 *
32 30 * This streams module collects incoming messages from modules below
33 31 * it on the stream and buffers them up into a smaller number of
34 32 * aggregated messages. Its main purpose is to reduce overhead by
35 33 * cutting down on the number of read (or getmsg) calls its client
36 34 * user process makes.
37 35 * - only M_DATA is buffered.
38 36 * - multithreading assumes configured as D_MTQPAIR
39 37 * - packets are lost only if flag SB_NO_HEADER is clear and buffer
40 38 * allocation fails.
41 39 * - in order message transmission. This is enforced for messages other
42 40 * than high priority messages.
43 41 * - zero length messages on the read side are not passed up the
44 42 * stream but used internally for synchronization.
45 43 * FLAGS:
46 44 * - SB_NO_PROTO_CVT - no conversion of M_PROTO messages to M_DATA.
47 45 * (conversion is the default for backwards compatibility
48 46 * hence the negative logic).
49 47 * - SB_NO_HEADER - no headers in buffered data.
50 48 * (adding headers is the default for backwards compatibility
51 49 * hence the negative logic).
52 50 * - SB_DEFER_CHUNK - provides improved response time in question-answer
53 51 * applications. Buffering is not enabled until the second message
54 52 * is received on the read side within the sb_ticks interval.
55 53 * This option will often be used in combination with flag SB_SEND_ON_WRITE.
56 54 * - SB_SEND_ON_WRITE - a write message results in any pending buffered read
57 55 * data being immediately sent upstream.
58 56 * - SB_NO_DROPS - bufmod behaves transparently in flow control and propagates
59 57 * the blocked flow condition downstream. If this flag is clear (default)
60 58 * messages will be dropped if the upstream flow is blocked.
61 59 */
62 60
63 61
64 62 #include <sys/types.h>
65 63 #include <sys/errno.h>
66 64 #include <sys/debug.h>
67 65 #include <sys/stropts.h>
68 66 #include <sys/time.h>
69 67 #include <sys/stream.h>
70 68 #include <sys/conf.h>
71 69 #include <sys/ddi.h>
72 70 #include <sys/sunddi.h>
73 71 #include <sys/kmem.h>
74 72 #include <sys/strsun.h>
75 73 #include <sys/bufmod.h>
76 74 #include <sys/modctl.h>
77 75 #include <sys/isa_defs.h>
78 76
79 77 /*
80 78 * Per-Stream state information.
81 79 *
82 80 * If sb_ticks is negative, we don't deliver chunks until they're
83 81 * full. If it's zero, we deliver every packet as it arrives. (In
84 82 * this case we force sb_chunk to zero, to make the implementation
85 83 * easier.) Otherwise, sb_ticks gives the number of ticks in a
86 84 * buffering interval. The interval begins when the a read side data
87 85 * message is received and a timeout is not active. If sb_snap is
88 86 * zero, no truncation of the msg is done.
89 87 */
90 88 struct sb {
91 89 queue_t *sb_rq; /* our rq */
92 90 mblk_t *sb_mp; /* partial chunk */
93 91 mblk_t *sb_head; /* pre-allocated space for the next header */
94 92 mblk_t *sb_tail; /* first mblk of last message appended */
95 93 uint_t sb_mlen; /* sb_mp length */
96 94 uint_t sb_mcount; /* input msg count in sb_mp */
97 95 uint_t sb_chunk; /* max chunk size */
98 96 clock_t sb_ticks; /* timeout interval */
99 97 timeout_id_t sb_timeoutid; /* qtimeout() id */
100 98 uint_t sb_drops; /* cumulative # discarded msgs */
101 99 uint_t sb_snap; /* snapshot length */
102 100 uint_t sb_flags; /* flags field */
103 101 uint_t sb_state; /* state variable */
104 102 };
105 103
106 104 /*
107 105 * Function prototypes.
108 106 */
109 107 static int sbopen(queue_t *, dev_t *, int, int, cred_t *);
110 108 static int sbclose(queue_t *, int, cred_t *);
111 109 static void sbwput(queue_t *, mblk_t *);
112 110 static void sbrput(queue_t *, mblk_t *);
113 111 static void sbrsrv(queue_t *);
114 112 static void sbioctl(queue_t *, mblk_t *);
115 113 static void sbaddmsg(queue_t *, mblk_t *);
116 114 static void sbtick(void *);
117 115 static void sbclosechunk(struct sb *);
118 116 static void sbsendit(queue_t *, mblk_t *);
119 117
120 118 static struct module_info sb_minfo = {
121 119 21, /* mi_idnum */
122 120 "bufmod", /* mi_idname */
123 121 0, /* mi_minpsz */
124 122 INFPSZ, /* mi_maxpsz */
125 123 1, /* mi_hiwat */
126 124 0 /* mi_lowat */
127 125 };
128 126
129 127 static struct qinit sb_rinit = {
130 128 (int (*)())sbrput, /* qi_putp */
131 129 (int (*)())sbrsrv, /* qi_srvp */
132 130 sbopen, /* qi_qopen */
133 131 sbclose, /* qi_qclose */
134 132 NULL, /* qi_qadmin */
135 133 &sb_minfo, /* qi_minfo */
136 134 NULL /* qi_mstat */
137 135 };
138 136
139 137 static struct qinit sb_winit = {
140 138 (int (*)())sbwput, /* qi_putp */
141 139 NULL, /* qi_srvp */
142 140 NULL, /* qi_qopen */
143 141 NULL, /* qi_qclose */
144 142 NULL, /* qi_qadmin */
145 143 &sb_minfo, /* qi_minfo */
146 144 NULL /* qi_mstat */
147 145 };
148 146
149 147 static struct streamtab sb_info = {
150 148 &sb_rinit, /* st_rdinit */
151 149 &sb_winit, /* st_wrinit */
152 150 NULL, /* st_muxrinit */
153 151 NULL /* st_muxwinit */
154 152 };
155 153
156 154
157 155 /*
158 156 * This is the loadable module wrapper.
159 157 */
160 158
161 159 static struct fmodsw fsw = {
162 160 "bufmod",
163 161 &sb_info,
164 162 D_MTQPAIR | D_MP
165 163 };
↓ open down ↓ |
127 lines elided |
↑ open up ↑ |
166 164
167 165 /*
168 166 * Module linkage information for the kernel.
169 167 */
170 168
171 169 static struct modlstrmod modlstrmod = {
172 170 &mod_strmodops, "streams buffer mod", &fsw
173 171 };
174 172
175 173 static struct modlinkage modlinkage = {
176 - MODREV_1, &modlstrmod, NULL
174 + MODREV_1, { &modlstrmod, NULL }
177 175 };
178 176
179 177
180 178 int
181 179 _init(void)
182 180 {
183 181 return (mod_install(&modlinkage));
184 182 }
185 183
186 184 int
187 185 _fini(void)
188 186 {
189 187 return (mod_remove(&modlinkage));
190 188 }
191 189
192 190 int
193 191 _info(struct modinfo *modinfop)
194 192 {
195 193 return (mod_info(&modlinkage, modinfop));
196 194 }
197 195
198 196
199 197 /* ARGSUSED */
200 198 static int
201 199 sbopen(queue_t *rq, dev_t *dev, int oflag, int sflag, cred_t *crp)
202 200 {
203 201 struct sb *sbp;
204 202 ASSERT(rq);
205 203
206 204 if (sflag != MODOPEN)
207 205 return (EINVAL);
208 206
209 207 if (rq->q_ptr)
210 208 return (0);
211 209
212 210 /*
213 211 * Allocate and initialize per-Stream structure.
214 212 */
215 213 sbp = kmem_alloc(sizeof (struct sb), KM_SLEEP);
216 214 sbp->sb_rq = rq;
217 215 sbp->sb_ticks = -1;
218 216 sbp->sb_chunk = SB_DFLT_CHUNK;
219 217 sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
220 218 sbp->sb_mlen = 0;
221 219 sbp->sb_mcount = 0;
222 220 sbp->sb_timeoutid = 0;
223 221 sbp->sb_drops = 0;
224 222 sbp->sb_snap = 0;
225 223 sbp->sb_flags = 0;
226 224 sbp->sb_state = 0;
227 225
228 226 rq->q_ptr = WR(rq)->q_ptr = sbp;
229 227
230 228 qprocson(rq);
231 229
232 230
233 231 return (0);
234 232 }
235 233
236 234 /* ARGSUSED1 */
237 235 static int
238 236 sbclose(queue_t *rq, int flag, cred_t *credp)
239 237 {
240 238 struct sb *sbp = (struct sb *)rq->q_ptr;
241 239
242 240 ASSERT(sbp);
243 241
244 242 qprocsoff(rq);
245 243 /*
246 244 * Cancel an outstanding timeout
247 245 */
248 246 if (sbp->sb_timeoutid != 0) {
249 247 (void) quntimeout(rq, sbp->sb_timeoutid);
250 248 sbp->sb_timeoutid = 0;
251 249 }
252 250 /*
253 251 * Free the current chunk.
254 252 */
255 253 if (sbp->sb_mp) {
256 254 freemsg(sbp->sb_mp);
257 255 sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
258 256 sbp->sb_mlen = 0;
259 257 }
260 258
261 259 /*
262 260 * Free the per-Stream structure.
263 261 */
264 262 kmem_free((caddr_t)sbp, sizeof (struct sb));
265 263 rq->q_ptr = WR(rq)->q_ptr = NULL;
266 264
267 265 return (0);
268 266 }
269 267
270 268 /*
271 269 * the correction factor is introduced to compensate for
272 270 * whatever assumptions the modules below have made about
273 271 * how much traffic is flowing through the stream and the fact
274 272 * that bufmod may be snipping messages with the sb_snap length.
275 273 */
276 274 #define SNIT_HIWAT(msgsize, fudge) ((4 * msgsize * fudge) + 512)
277 275 #define SNIT_LOWAT(msgsize, fudge) ((2 * msgsize * fudge) + 256)
278 276
279 277
280 278 static void
281 279 sbioc(queue_t *wq, mblk_t *mp)
282 280 {
283 281 struct iocblk *iocp;
284 282 struct sb *sbp = (struct sb *)wq->q_ptr;
285 283 clock_t ticks;
286 284 mblk_t *mop;
287 285
288 286 iocp = (struct iocblk *)mp->b_rptr;
289 287
290 288 switch (iocp->ioc_cmd) {
291 289 case SBIOCGCHUNK:
292 290 case SBIOCGSNAP:
293 291 case SBIOCGFLAGS:
294 292 case SBIOCGTIME:
295 293 miocack(wq, mp, 0, 0);
296 294 return;
297 295
298 296 case SBIOCSTIME:
299 297 #ifdef _SYSCALL32_IMPL
300 298 if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
301 299 struct timeval32 *t32;
302 300
303 301 t32 = (struct timeval32 *)mp->b_cont->b_rptr;
304 302 if (t32->tv_sec < 0 || t32->tv_usec < 0) {
305 303 miocnak(wq, mp, 0, EINVAL);
306 304 break;
307 305 }
308 306 ticks = TIMEVAL_TO_TICK(t32);
309 307 } else
310 308 #endif /* _SYSCALL32_IMPL */
311 309 {
312 310 struct timeval *tb;
313 311
314 312 tb = (struct timeval *)mp->b_cont->b_rptr;
315 313
316 314 if (tb->tv_sec < 0 || tb->tv_usec < 0) {
317 315 miocnak(wq, mp, 0, EINVAL);
318 316 break;
319 317 }
320 318 ticks = TIMEVAL_TO_TICK(tb);
321 319 }
322 320 sbp->sb_ticks = ticks;
323 321 if (ticks == 0)
324 322 sbp->sb_chunk = 0;
325 323 miocack(wq, mp, 0, 0);
326 324 sbclosechunk(sbp);
327 325 return;
328 326
329 327 case SBIOCSCHUNK:
330 328 /*
331 329 * set up hi/lo water marks on stream head read queue.
332 330 * unlikely to run out of resources. Fix at later date.
333 331 */
334 332 if ((mop = allocb(sizeof (struct stroptions),
335 333 BPRI_MED)) != NULL) {
336 334 struct stroptions *sop;
337 335 uint_t chunk;
338 336
339 337 chunk = *(uint_t *)mp->b_cont->b_rptr;
340 338 mop->b_datap->db_type = M_SETOPTS;
341 339 mop->b_wptr += sizeof (struct stroptions);
342 340 sop = (struct stroptions *)mop->b_rptr;
343 341 sop->so_flags = SO_HIWAT | SO_LOWAT;
344 342 sop->so_hiwat = SNIT_HIWAT(chunk, 1);
345 343 sop->so_lowat = SNIT_LOWAT(chunk, 1);
346 344 qreply(wq, mop);
347 345 }
348 346
349 347 sbp->sb_chunk = *(uint_t *)mp->b_cont->b_rptr;
350 348 miocack(wq, mp, 0, 0);
351 349 sbclosechunk(sbp);
352 350 return;
353 351
354 352 case SBIOCSFLAGS:
355 353 sbp->sb_flags = *(uint_t *)mp->b_cont->b_rptr;
356 354 miocack(wq, mp, 0, 0);
357 355 return;
358 356
359 357 case SBIOCSSNAP:
360 358 /*
361 359 * if chunking dont worry about effects of
362 360 * snipping of message size on head flow control
363 361 * since it has a relatively small bearing on the
364 362 * data rate onto the streamn head.
365 363 */
366 364 if (!sbp->sb_chunk) {
367 365 /*
368 366 * set up hi/lo water marks on stream head read queue.
369 367 * unlikely to run out of resources. Fix at later date.
370 368 */
371 369 if ((mop = allocb(sizeof (struct stroptions),
372 370 BPRI_MED)) != NULL) {
373 371 struct stroptions *sop;
374 372 uint_t snap;
375 373 int fudge;
376 374
377 375 snap = *(uint_t *)mp->b_cont->b_rptr;
378 376 mop->b_datap->db_type = M_SETOPTS;
379 377 mop->b_wptr += sizeof (struct stroptions);
380 378 sop = (struct stroptions *)mop->b_rptr;
381 379 sop->so_flags = SO_HIWAT | SO_LOWAT;
382 380 fudge = snap <= 100 ? 4 :
383 381 snap <= 400 ? 2 :
384 382 1;
385 383 sop->so_hiwat = SNIT_HIWAT(snap, fudge);
386 384 sop->so_lowat = SNIT_LOWAT(snap, fudge);
387 385 qreply(wq, mop);
388 386 }
389 387 }
390 388
391 389 sbp->sb_snap = *(uint_t *)mp->b_cont->b_rptr;
392 390 miocack(wq, mp, 0, 0);
393 391 return;
394 392
395 393 default:
396 394 ASSERT(0);
397 395 return;
398 396 }
399 397 }
400 398
401 399 /*
402 400 * Write-side put procedure. Its main task is to detect ioctls
403 401 * for manipulating the buffering state and hand them to sbioctl.
404 402 * Other message types are passed on through.
405 403 */
406 404 static void
407 405 sbwput(queue_t *wq, mblk_t *mp)
408 406 {
409 407 struct sb *sbp = (struct sb *)wq->q_ptr;
410 408 struct copyresp *resp;
411 409
412 410 if (sbp->sb_flags & SB_SEND_ON_WRITE)
413 411 sbclosechunk(sbp);
414 412 switch (mp->b_datap->db_type) {
415 413 case M_IOCTL:
416 414 sbioctl(wq, mp);
417 415 break;
418 416
419 417 case M_IOCDATA:
420 418 resp = (struct copyresp *)mp->b_rptr;
421 419 if (resp->cp_rval) {
422 420 /*
423 421 * Just free message on failure.
424 422 */
425 423 freemsg(mp);
426 424 break;
427 425 }
428 426
429 427 switch (resp->cp_cmd) {
430 428 case SBIOCSTIME:
431 429 case SBIOCSCHUNK:
432 430 case SBIOCSFLAGS:
433 431 case SBIOCSSNAP:
434 432 case SBIOCGTIME:
435 433 case SBIOCGCHUNK:
436 434 case SBIOCGSNAP:
437 435 case SBIOCGFLAGS:
438 436 sbioc(wq, mp);
439 437 break;
440 438
441 439 default:
442 440 putnext(wq, mp);
443 441 break;
444 442 }
445 443 break;
446 444
447 445 default:
448 446 putnext(wq, mp);
449 447 break;
450 448 }
451 449 }
452 450
453 451 /*
454 452 * Read-side put procedure. It's responsible for buffering up incoming
455 453 * messages and grouping them into aggregates according to the current
456 454 * buffering parameters.
457 455 */
458 456 static void
459 457 sbrput(queue_t *rq, mblk_t *mp)
460 458 {
461 459 struct sb *sbp = (struct sb *)rq->q_ptr;
462 460
463 461 ASSERT(sbp);
464 462
465 463 switch (mp->b_datap->db_type) {
466 464 case M_PROTO:
467 465 if (sbp->sb_flags & SB_NO_PROTO_CVT) {
468 466 sbclosechunk(sbp);
469 467 sbsendit(rq, mp);
470 468 break;
471 469 } else {
472 470 /*
473 471 * Convert M_PROTO to M_DATA.
474 472 */
475 473 mp->b_datap->db_type = M_DATA;
476 474 }
477 475 /* FALLTHRU */
478 476
479 477 case M_DATA:
480 478 if ((sbp->sb_flags & SB_DEFER_CHUNK) &&
481 479 !(sbp->sb_state & SB_FRCVD)) {
482 480 sbclosechunk(sbp);
483 481 sbsendit(rq, mp);
484 482 sbp->sb_state |= SB_FRCVD;
485 483 } else
486 484 sbaddmsg(rq, mp);
487 485
488 486 if ((sbp->sb_ticks > 0) && !(sbp->sb_timeoutid))
489 487 sbp->sb_timeoutid = qtimeout(sbp->sb_rq, sbtick,
490 488 sbp, sbp->sb_ticks);
491 489
492 490 break;
493 491
494 492 case M_FLUSH:
495 493 if (*mp->b_rptr & FLUSHR) {
496 494 /*
497 495 * Reset timeout, flush the chunk currently in
498 496 * progress, and start a new chunk.
499 497 */
500 498 if (sbp->sb_timeoutid) {
501 499 (void) quntimeout(sbp->sb_rq,
502 500 sbp->sb_timeoutid);
503 501 sbp->sb_timeoutid = 0;
504 502 }
505 503 if (sbp->sb_mp) {
506 504 freemsg(sbp->sb_mp);
507 505 sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
508 506 sbp->sb_mlen = 0;
509 507 sbp->sb_mcount = 0;
510 508 }
511 509 flushq(rq, FLUSHALL);
512 510 }
513 511 putnext(rq, mp);
514 512 break;
515 513
516 514 case M_CTL:
517 515 /*
518 516 * Zero-length M_CTL means our timeout() popped.
519 517 */
520 518 if (MBLKL(mp) == 0) {
521 519 freemsg(mp);
522 520 sbclosechunk(sbp);
523 521 } else {
524 522 sbclosechunk(sbp);
525 523 sbsendit(rq, mp);
526 524 }
527 525 break;
528 526
529 527 default:
530 528 if (mp->b_datap->db_type <= QPCTL) {
531 529 sbclosechunk(sbp);
532 530 sbsendit(rq, mp);
533 531 } else {
534 532 /* Note: out of band */
535 533 putnext(rq, mp);
536 534 }
537 535 break;
538 536 }
539 537 }
540 538
541 539 /*
542 540 * read service procedure.
543 541 */
544 542 /* ARGSUSED */
545 543 static void
546 544 sbrsrv(queue_t *rq)
547 545 {
548 546 mblk_t *mp;
549 547
550 548 /*
551 549 * High priority messages shouldn't get here but if
552 550 * one does, jam it through to avoid infinite loop.
553 551 */
554 552 while ((mp = getq(rq)) != NULL) {
555 553 if (!canputnext(rq) && (mp->b_datap->db_type <= QPCTL)) {
556 554 /* should only get here if SB_NO_SROPS */
557 555 (void) putbq(rq, mp);
558 556 return;
559 557 }
560 558 putnext(rq, mp);
561 559 }
562 560 }
563 561
564 562 /*
565 563 * Handle write-side M_IOCTL messages.
566 564 */
567 565 static void
568 566 sbioctl(queue_t *wq, mblk_t *mp)
569 567 {
570 568 struct sb *sbp = (struct sb *)wq->q_ptr;
571 569 struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
572 570 struct timeval *t;
573 571 clock_t ticks;
574 572 mblk_t *mop;
575 573 int transparent = iocp->ioc_count;
576 574 mblk_t *datamp;
577 575 int error;
578 576
579 577 switch (iocp->ioc_cmd) {
580 578 case SBIOCSTIME:
581 579 if (iocp->ioc_count == TRANSPARENT) {
582 580 #ifdef _SYSCALL32_IMPL
583 581 if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
584 582 mcopyin(mp, NULL, sizeof (struct timeval32),
585 583 NULL);
586 584 } else
587 585 #endif /* _SYSCALL32_IMPL */
588 586 {
589 587 mcopyin(mp, NULL, sizeof (*t), NULL);
590 588 }
591 589 qreply(wq, mp);
592 590 } else {
593 591 /*
594 592 * Verify argument length.
595 593 */
596 594 #ifdef _SYSCALL32_IMPL
597 595 if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
598 596 struct timeval32 *t32;
599 597
600 598 error = miocpullup(mp,
601 599 sizeof (struct timeval32));
602 600 if (error != 0) {
603 601 miocnak(wq, mp, 0, error);
604 602 break;
605 603 }
606 604 t32 = (struct timeval32 *)mp->b_cont->b_rptr;
607 605 if (t32->tv_sec < 0 || t32->tv_usec < 0) {
608 606 miocnak(wq, mp, 0, EINVAL);
609 607 break;
610 608 }
611 609 ticks = TIMEVAL_TO_TICK(t32);
612 610 } else
613 611 #endif /* _SYSCALL32_IMPL */
614 612 {
615 613 error = miocpullup(mp, sizeof (struct timeval));
616 614 if (error != 0) {
617 615 miocnak(wq, mp, 0, error);
618 616 break;
619 617 }
620 618
621 619 t = (struct timeval *)mp->b_cont->b_rptr;
622 620 if (t->tv_sec < 0 || t->tv_usec < 0) {
623 621 miocnak(wq, mp, 0, EINVAL);
624 622 break;
625 623 }
626 624 ticks = TIMEVAL_TO_TICK(t);
627 625 }
628 626 sbp->sb_ticks = ticks;
629 627 if (ticks == 0)
630 628 sbp->sb_chunk = 0;
631 629 miocack(wq, mp, 0, 0);
632 630 sbclosechunk(sbp);
633 631 }
634 632 break;
635 633
636 634 case SBIOCGTIME: {
637 635 struct timeval *t;
638 636
639 637 /*
640 638 * Verify argument length.
641 639 */
642 640 if (transparent != TRANSPARENT) {
643 641 #ifdef _SYSCALL32_IMPL
644 642 if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
645 643 error = miocpullup(mp,
646 644 sizeof (struct timeval32));
647 645 if (error != 0) {
648 646 miocnak(wq, mp, 0, error);
649 647 break;
650 648 }
651 649 } else
652 650 #endif /* _SYSCALL32_IMPL */
653 651 error = miocpullup(mp, sizeof (struct timeval));
654 652 if (error != 0) {
655 653 miocnak(wq, mp, 0, error);
656 654 break;
657 655 }
658 656 }
659 657
660 658 /*
661 659 * If infinite timeout, return range error
662 660 * for the ioctl.
663 661 */
664 662 if (sbp->sb_ticks < 0) {
665 663 miocnak(wq, mp, 0, ERANGE);
666 664 break;
667 665 }
668 666
669 667 #ifdef _SYSCALL32_IMPL
670 668 if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
671 669 struct timeval32 *t32;
672 670
673 671 if (transparent == TRANSPARENT) {
674 672 datamp = allocb(sizeof (*t32), BPRI_MED);
675 673 if (datamp == NULL) {
676 674 miocnak(wq, mp, 0, EAGAIN);
677 675 break;
678 676 }
679 677 mcopyout(mp, NULL, sizeof (*t32), NULL, datamp);
680 678 }
681 679
682 680 t32 = (struct timeval32 *)mp->b_cont->b_rptr;
683 681 TICK_TO_TIMEVAL32(sbp->sb_ticks, t32);
684 682
685 683 if (transparent == TRANSPARENT)
686 684 qreply(wq, mp);
687 685 else
688 686 miocack(wq, mp, sizeof (*t32), 0);
689 687 } else
690 688 #endif /* _SYSCALL32_IMPL */
691 689 {
692 690 if (transparent == TRANSPARENT) {
693 691 datamp = allocb(sizeof (*t), BPRI_MED);
694 692 if (datamp == NULL) {
695 693 miocnak(wq, mp, 0, EAGAIN);
696 694 break;
697 695 }
698 696 mcopyout(mp, NULL, sizeof (*t), NULL, datamp);
699 697 }
700 698
701 699 t = (struct timeval *)mp->b_cont->b_rptr;
702 700 TICK_TO_TIMEVAL(sbp->sb_ticks, t);
703 701
704 702 if (transparent == TRANSPARENT)
705 703 qreply(wq, mp);
706 704 else
707 705 miocack(wq, mp, sizeof (*t), 0);
708 706 }
709 707 break;
710 708 }
711 709
712 710 case SBIOCCTIME:
713 711 sbp->sb_ticks = -1;
714 712 miocack(wq, mp, 0, 0);
715 713 break;
716 714
717 715 case SBIOCSCHUNK:
718 716 if (iocp->ioc_count == TRANSPARENT) {
719 717 mcopyin(mp, NULL, sizeof (uint_t), NULL);
720 718 qreply(wq, mp);
721 719 } else {
722 720 /*
723 721 * Verify argument length.
724 722 */
725 723 error = miocpullup(mp, sizeof (uint_t));
726 724 if (error != 0) {
727 725 miocnak(wq, mp, 0, error);
728 726 break;
729 727 }
730 728
731 729 /*
732 730 * set up hi/lo water marks on stream head read queue.
733 731 * unlikely to run out of resources. Fix at later date.
734 732 */
735 733 if ((mop = allocb(sizeof (struct stroptions),
736 734 BPRI_MED)) != NULL) {
737 735 struct stroptions *sop;
738 736 uint_t chunk;
739 737
740 738 chunk = *(uint_t *)mp->b_cont->b_rptr;
741 739 mop->b_datap->db_type = M_SETOPTS;
742 740 mop->b_wptr += sizeof (struct stroptions);
743 741 sop = (struct stroptions *)mop->b_rptr;
744 742 sop->so_flags = SO_HIWAT | SO_LOWAT;
745 743 sop->so_hiwat = SNIT_HIWAT(chunk, 1);
746 744 sop->so_lowat = SNIT_LOWAT(chunk, 1);
747 745 qreply(wq, mop);
748 746 }
749 747
750 748 sbp->sb_chunk = *(uint_t *)mp->b_cont->b_rptr;
751 749 miocack(wq, mp, 0, 0);
752 750 sbclosechunk(sbp);
753 751 }
754 752 break;
755 753
756 754 case SBIOCGCHUNK:
757 755 /*
758 756 * Verify argument length.
759 757 */
760 758 if (transparent != TRANSPARENT) {
761 759 error = miocpullup(mp, sizeof (uint_t));
762 760 if (error != 0) {
763 761 miocnak(wq, mp, 0, error);
764 762 break;
765 763 }
766 764 }
767 765
768 766 if (transparent == TRANSPARENT) {
769 767 datamp = allocb(sizeof (uint_t), BPRI_MED);
770 768 if (datamp == NULL) {
771 769 miocnak(wq, mp, 0, EAGAIN);
772 770 break;
773 771 }
774 772 mcopyout(mp, NULL, sizeof (uint_t), NULL, datamp);
775 773 }
776 774
777 775 *(uint_t *)mp->b_cont->b_rptr = sbp->sb_chunk;
778 776
779 777 if (transparent == TRANSPARENT)
780 778 qreply(wq, mp);
781 779 else
782 780 miocack(wq, mp, sizeof (uint_t), 0);
783 781 break;
784 782
785 783 case SBIOCSSNAP:
786 784 if (iocp->ioc_count == TRANSPARENT) {
787 785 mcopyin(mp, NULL, sizeof (uint_t), NULL);
788 786 qreply(wq, mp);
789 787 } else {
790 788 /*
791 789 * Verify argument length.
792 790 */
793 791 error = miocpullup(mp, sizeof (uint_t));
794 792 if (error != 0) {
795 793 miocnak(wq, mp, 0, error);
796 794 break;
797 795 }
798 796
799 797 /*
800 798 * if chunking dont worry about effects of
801 799 * snipping of message size on head flow control
802 800 * since it has a relatively small bearing on the
803 801 * data rate onto the streamn head.
804 802 */
805 803 if (!sbp->sb_chunk) {
806 804 /*
807 805 * set up hi/lo water marks on stream
808 806 * head read queue. unlikely to run out
809 807 * of resources. Fix at later date.
810 808 */
811 809 if ((mop = allocb(sizeof (struct stroptions),
812 810 BPRI_MED)) != NULL) {
813 811 struct stroptions *sop;
814 812 uint_t snap;
815 813 int fudge;
816 814
817 815 snap = *(uint_t *)mp->b_cont->b_rptr;
818 816 mop->b_datap->db_type = M_SETOPTS;
819 817 mop->b_wptr += sizeof (*sop);
820 818 sop = (struct stroptions *)mop->b_rptr;
821 819 sop->so_flags = SO_HIWAT | SO_LOWAT;
822 820 fudge = (snap <= 100) ? 4 :
823 821 (snap <= 400) ? 2 : 1;
824 822 sop->so_hiwat = SNIT_HIWAT(snap, fudge);
825 823 sop->so_lowat = SNIT_LOWAT(snap, fudge);
826 824 qreply(wq, mop);
827 825 }
828 826 }
829 827
830 828 sbp->sb_snap = *(uint_t *)mp->b_cont->b_rptr;
831 829
832 830 miocack(wq, mp, 0, 0);
833 831 }
834 832 break;
835 833
836 834 case SBIOCGSNAP:
837 835 /*
838 836 * Verify argument length
839 837 */
840 838 if (transparent != TRANSPARENT) {
841 839 error = miocpullup(mp, sizeof (uint_t));
842 840 if (error != 0) {
843 841 miocnak(wq, mp, 0, error);
844 842 break;
845 843 }
846 844 }
847 845
848 846 if (transparent == TRANSPARENT) {
849 847 datamp = allocb(sizeof (uint_t), BPRI_MED);
850 848 if (datamp == NULL) {
851 849 miocnak(wq, mp, 0, EAGAIN);
852 850 break;
853 851 }
854 852 mcopyout(mp, NULL, sizeof (uint_t), NULL, datamp);
855 853 }
856 854
857 855 *(uint_t *)mp->b_cont->b_rptr = sbp->sb_snap;
858 856
859 857 if (transparent == TRANSPARENT)
860 858 qreply(wq, mp);
861 859 else
862 860 miocack(wq, mp, sizeof (uint_t), 0);
863 861 break;
864 862
865 863 case SBIOCSFLAGS:
866 864 /*
867 865 * set the flags.
868 866 */
869 867 if (iocp->ioc_count == TRANSPARENT) {
870 868 mcopyin(mp, NULL, sizeof (uint_t), NULL);
871 869 qreply(wq, mp);
872 870 } else {
873 871 error = miocpullup(mp, sizeof (uint_t));
874 872 if (error != 0) {
875 873 miocnak(wq, mp, 0, error);
876 874 break;
877 875 }
878 876 sbp->sb_flags = *(uint_t *)mp->b_cont->b_rptr;
879 877 miocack(wq, mp, 0, 0);
880 878 }
881 879 break;
882 880
883 881 case SBIOCGFLAGS:
884 882 /*
885 883 * Verify argument length
886 884 */
887 885 if (transparent != TRANSPARENT) {
888 886 error = miocpullup(mp, sizeof (uint_t));
889 887 if (error != 0) {
890 888 miocnak(wq, mp, 0, error);
891 889 break;
892 890 }
893 891 }
894 892
895 893 if (transparent == TRANSPARENT) {
896 894 datamp = allocb(sizeof (uint_t), BPRI_MED);
897 895 if (datamp == NULL) {
898 896 miocnak(wq, mp, 0, EAGAIN);
899 897 break;
900 898 }
901 899 mcopyout(mp, NULL, sizeof (uint_t), NULL, datamp);
902 900 }
903 901
904 902 *(uint_t *)mp->b_cont->b_rptr = sbp->sb_flags;
905 903
906 904 if (transparent == TRANSPARENT)
907 905 qreply(wq, mp);
908 906 else
909 907 miocack(wq, mp, sizeof (uint_t), 0);
910 908 break;
911 909
912 910
913 911 default:
914 912 putnext(wq, mp);
915 913 break;
916 914 }
917 915 }
918 916
919 917 /*
920 918 * Given a length l, calculate the amount of extra storage
921 919 * required to round it up to the next multiple of the alignment a.
922 920 */
923 921 #define RoundUpAmt(l, a) ((l) % (a) ? (a) - ((l) % (a)) : 0)
924 922 /*
925 923 * Calculate additional amount of space required for alignment.
926 924 */
927 925 #define Align(l) RoundUpAmt(l, sizeof (ulong_t))
928 926 /*
929 927 * Smallest possible message size when headers are enabled.
930 928 * This is used to calculate whether a chunk is nearly full.
931 929 */
932 930 #define SMALLEST_MESSAGE sizeof (struct sb_hdr) + _POINTER_ALIGNMENT
933 931
934 932 /*
935 933 * Process a read-side M_DATA message.
936 934 *
937 935 * If the currently accumulating chunk doesn't have enough room
938 936 * for the message, close off the chunk, pass it upward, and start
939 937 * a new one. Then add the message to the current chunk, taking
940 938 * account of the possibility that the message's size exceeds the
941 939 * chunk size.
942 940 *
943 941 * If headers are enabled add an sb_hdr header and trailing alignment padding.
944 942 *
945 943 * To optimise performance the total number of msgbs should be kept
946 944 * to a minimum. This is achieved by using any remaining space in message N
947 945 * for both its own padding as well as the header of message N+1 if possible.
948 946 * If there's insufficient space we allocate one message to hold this 'wrapper'.
949 947 * (there's likely to be space beyond message N, since allocb would have
950 948 * rounded up the required size to one of the dblk_sizes).
951 949 *
952 950 */
953 951 static void
954 952 sbaddmsg(queue_t *rq, mblk_t *mp)
955 953 {
956 954 struct sb *sbp;
957 955 struct timeval t;
958 956 struct sb_hdr hp;
959 957 mblk_t *wrapper; /* padding for msg N, header for msg N+1 */
960 958 mblk_t *last; /* last mblk of current message */
961 959 size_t wrapperlen; /* length of header + padding */
962 960 size_t origlen; /* data length before truncation */
963 961 size_t pad; /* bytes required to align header */
964 962
965 963 sbp = (struct sb *)rq->q_ptr;
966 964
967 965 origlen = msgdsize(mp);
968 966
969 967 /*
970 968 * Truncate the message.
971 969 */
972 970 if ((sbp->sb_snap > 0) && (origlen > sbp->sb_snap) &&
973 971 (adjmsg(mp, -(origlen - sbp->sb_snap)) == 1))
974 972 hp.sbh_totlen = hp.sbh_msglen = sbp->sb_snap;
975 973 else
976 974 hp.sbh_totlen = hp.sbh_msglen = origlen;
977 975
978 976 if (sbp->sb_flags & SB_NO_HEADER) {
979 977
980 978 /*
981 979 * Would the inclusion of this message overflow the current
982 980 * chunk? If so close the chunk off and start a new one.
983 981 */
984 982 if ((hp.sbh_totlen + sbp->sb_mlen) > sbp->sb_chunk)
985 983 sbclosechunk(sbp);
986 984 /*
987 985 * First message too big for chunk - just send it up.
988 986 * This will always be true when we're not chunking.
989 987 */
990 988 if (hp.sbh_totlen > sbp->sb_chunk) {
991 989 sbsendit(rq, mp);
992 990 return;
993 991 }
994 992
995 993 /*
996 994 * We now know that the msg will fit in the chunk.
997 995 * Link it onto the end of the chunk.
998 996 * Since linkb() walks the entire chain, we keep a pointer to
999 997 * the first mblk of the last msgb added and call linkb on that
1000 998 * that last message, rather than performing the
1001 999 * O(n) linkb() operation on the whole chain.
1002 1000 * sb_head isn't needed in this SB_NO_HEADER mode.
1003 1001 */
1004 1002 if (sbp->sb_mp)
1005 1003 linkb(sbp->sb_tail, mp);
1006 1004 else
1007 1005 sbp->sb_mp = mp;
1008 1006
1009 1007 sbp->sb_tail = mp;
1010 1008 sbp->sb_mlen += hp.sbh_totlen;
1011 1009 sbp->sb_mcount++;
1012 1010 } else {
1013 1011 /* Timestamp must be done immediately */
1014 1012 uniqtime(&t);
1015 1013 TIMEVAL_TO_TIMEVAL32(&hp.sbh_timestamp, &t);
1016 1014
1017 1015 pad = Align(hp.sbh_totlen);
1018 1016 hp.sbh_totlen += sizeof (hp);
1019 1017 hp.sbh_totlen += pad;
1020 1018
1021 1019 /*
1022 1020 * Would the inclusion of this message overflow the current
1023 1021 * chunk? If so close the chunk off and start a new one.
1024 1022 */
1025 1023 if ((hp.sbh_totlen + sbp->sb_mlen) > sbp->sb_chunk)
1026 1024 sbclosechunk(sbp);
1027 1025
1028 1026 if (sbp->sb_head == NULL) {
1029 1027 /* Allocate leading header of new chunk */
1030 1028 sbp->sb_head = allocb(sizeof (hp), BPRI_MED);
1031 1029 if (sbp->sb_head == NULL) {
1032 1030 /*
1033 1031 * Memory allocation failure.
1034 1032 * This will need to be revisited
1035 1033 * since using certain flag combinations
1036 1034 * can result in messages being dropped
1037 1035 * silently.
1038 1036 */
1039 1037 freemsg(mp);
1040 1038 sbp->sb_drops++;
1041 1039 return;
1042 1040 }
1043 1041 sbp->sb_mp = sbp->sb_head;
1044 1042 }
1045 1043
1046 1044 /*
1047 1045 * Copy header into message
1048 1046 */
1049 1047 hp.sbh_drops = sbp->sb_drops;
1050 1048 hp.sbh_origlen = origlen;
1051 1049 (void) memcpy(sbp->sb_head->b_wptr, (char *)&hp, sizeof (hp));
1052 1050 sbp->sb_head->b_wptr += sizeof (hp);
1053 1051
1054 1052 ASSERT(sbp->sb_head->b_wptr <= sbp->sb_head->b_datap->db_lim);
1055 1053
1056 1054 /*
1057 1055 * Join message to the chunk
1058 1056 */
1059 1057 linkb(sbp->sb_head, mp);
1060 1058
1061 1059 sbp->sb_mcount++;
1062 1060 sbp->sb_mlen += hp.sbh_totlen;
1063 1061
1064 1062 /*
1065 1063 * If the first message alone is too big for the chunk close
1066 1064 * the chunk now.
1067 1065 * If the next message would immediately cause the chunk to
1068 1066 * overflow we may as well close the chunk now. The next
1069 1067 * message is certain to be at least SMALLEST_MESSAGE size.
1070 1068 */
1071 1069 if (hp.sbh_totlen + SMALLEST_MESSAGE > sbp->sb_chunk) {
1072 1070 sbclosechunk(sbp);
1073 1071 return;
1074 1072 }
1075 1073
1076 1074 /*
1077 1075 * Find space for the wrapper. The wrapper consists of:
1078 1076 *
1079 1077 * 1) Padding for this message (this is to ensure each header
1080 1078 * begins on an 8 byte boundary in the userland buffer).
1081 1079 *
1082 1080 * 2) Space for the next message's header, in case the next
1083 1081 * next message will fit in this chunk.
1084 1082 *
1085 1083 * It may be possible to append the wrapper to the last mblk
1086 1084 * of the message, but only if we 'own' the data. If the dblk
1087 1085 * has been shared through dupmsg() we mustn't alter it.
1088 1086 */
1089 1087
1090 1088 wrapperlen = (sizeof (hp) + pad);
1091 1089
1092 1090 /* Is there space for the wrapper beyond the message's data ? */
1093 1091 for (last = mp; last->b_cont; last = last->b_cont)
1094 1092 ;
1095 1093
1096 1094 if ((wrapperlen <= MBLKTAIL(last)) &&
1097 1095 (last->b_datap->db_ref == 1)) {
1098 1096 if (pad > 0) {
1099 1097 /*
1100 1098 * Pad with zeroes to the next pointer boundary
1101 1099 * (we don't want to disclose kernel data to
1102 1100 * users), then advance wptr.
1103 1101 */
1104 1102 (void) memset(last->b_wptr, 0, pad);
1105 1103 last->b_wptr += pad;
1106 1104 }
1107 1105 /* Remember where to write the header information */
1108 1106 sbp->sb_head = last;
1109 1107 } else {
1110 1108 /* Have to allocate additional space for the wrapper */
1111 1109 wrapper = allocb(wrapperlen, BPRI_MED);
1112 1110 if (wrapper == NULL) {
1113 1111 sbclosechunk(sbp);
1114 1112 return;
1115 1113 }
1116 1114 if (pad > 0) {
1117 1115 /*
1118 1116 * Pad with zeroes (we don't want to disclose
1119 1117 * kernel data to users).
1120 1118 */
1121 1119 (void) memset(wrapper->b_wptr, 0, pad);
1122 1120 wrapper->b_wptr += pad;
1123 1121 }
1124 1122 /* Link the wrapper msg onto the end of the chunk */
1125 1123 linkb(mp, wrapper);
1126 1124 /* Remember to write the next header in this wrapper */
1127 1125 sbp->sb_head = wrapper;
1128 1126 }
1129 1127 }
1130 1128 }
1131 1129
1132 1130 /*
1133 1131 * Called from timeout().
1134 1132 * Signal a timeout by passing a zero-length M_CTL msg in the read-side
1135 1133 * to synchronize with any active module threads (open, close, wput, rput).
1136 1134 */
1137 1135 static void
1138 1136 sbtick(void *arg)
1139 1137 {
1140 1138 struct sb *sbp = arg;
1141 1139 queue_t *rq;
1142 1140
1143 1141 ASSERT(sbp);
1144 1142
1145 1143 rq = sbp->sb_rq;
1146 1144 sbp->sb_timeoutid = 0; /* timeout has fired */
1147 1145
1148 1146 if (putctl(rq, M_CTL) == 0) /* failure */
1149 1147 sbp->sb_timeoutid = qtimeout(rq, sbtick, sbp, sbp->sb_ticks);
1150 1148 }
1151 1149
1152 1150 /*
1153 1151 * Close off the currently accumulating chunk and pass
1154 1152 * it upward. Takes care of resetting timers as well.
1155 1153 *
1156 1154 * This routine is called both directly and as a result
1157 1155 * of the chunk timeout expiring.
1158 1156 */
1159 1157 static void
1160 1158 sbclosechunk(struct sb *sbp)
1161 1159 {
1162 1160 mblk_t *mp;
1163 1161 queue_t *rq;
1164 1162
1165 1163 ASSERT(sbp);
1166 1164
1167 1165 if (sbp->sb_timeoutid) {
1168 1166 (void) quntimeout(sbp->sb_rq, sbp->sb_timeoutid);
1169 1167 sbp->sb_timeoutid = 0;
1170 1168 }
1171 1169
1172 1170 mp = sbp->sb_mp;
1173 1171 rq = sbp->sb_rq;
1174 1172
1175 1173 /*
1176 1174 * If there's currently a chunk in progress, close it off
1177 1175 * and try to send it up.
1178 1176 */
1179 1177 if (mp) {
1180 1178 sbsendit(rq, mp);
1181 1179 }
1182 1180
1183 1181 /*
1184 1182 * Clear old chunk. Ready for new msgs.
1185 1183 */
1186 1184 sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
1187 1185 sbp->sb_mlen = 0;
1188 1186 sbp->sb_mcount = 0;
1189 1187 if (sbp->sb_flags & SB_DEFER_CHUNK)
1190 1188 sbp->sb_state &= ~SB_FRCVD;
1191 1189
1192 1190 }
1193 1191
1194 1192 static void
1195 1193 sbsendit(queue_t *rq, mblk_t *mp)
1196 1194 {
1197 1195 struct sb *sbp = (struct sb *)rq->q_ptr;
1198 1196
1199 1197 if (!canputnext(rq)) {
1200 1198 if (sbp->sb_flags & SB_NO_DROPS)
1201 1199 (void) putq(rq, mp);
1202 1200 else {
1203 1201 freemsg(mp);
1204 1202 sbp->sb_drops += sbp->sb_mcount;
1205 1203 }
1206 1204 return;
1207 1205 }
1208 1206 /*
1209 1207 * If there are messages on the q already, keep
1210 1208 * queueing them since they need to be processed in order.
1211 1209 */
1212 1210 if (qsize(rq) > 0) {
1213 1211 /* should only get here if SB_NO_DROPS */
1214 1212 (void) putq(rq, mp);
1215 1213 }
1216 1214 else
1217 1215 putnext(rq, mp);
1218 1216 }
↓ open down ↓ |
1032 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX