18329232eSGordon Ross /*
28329232eSGordon Ross * CDDL HEADER START
38329232eSGordon Ross *
48329232eSGordon Ross * The contents of this file are subject to the terms of the
58329232eSGordon Ross * Common Development and Distribution License (the "License").
68329232eSGordon Ross * You may not use this file except in compliance with the License.
78329232eSGordon Ross *
88329232eSGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98329232eSGordon Ross * or http://www.opensolaris.org/os/licensing.
108329232eSGordon Ross * See the License for the specific language governing permissions
118329232eSGordon Ross * and limitations under the License.
128329232eSGordon Ross *
138329232eSGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
148329232eSGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158329232eSGordon Ross * If applicable, add the following below this CDDL HEADER, with the
168329232eSGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
178329232eSGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
188329232eSGordon Ross *
198329232eSGordon Ross * CDDL HEADER END
208329232eSGordon Ross */
218329232eSGordon Ross /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
228329232eSGordon Ross /* All Rights Reserved */
238329232eSGordon Ross
248329232eSGordon Ross /*
258329232eSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
268329232eSGordon Ross * Use is subject to license terms.
278329232eSGordon Ross *
288329232eSGordon Ross * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
29*9b664393SGarrett D'Amore * Copyright 2022 Garrett D'Amore
308329232eSGordon Ross */
318329232eSGordon Ross
328329232eSGordon Ross #include <sys/types.h>
338329232eSGordon Ross #include <sys/param.h>
348329232eSGordon Ross #include <sys/thread.h>
358329232eSGordon Ross #include <sys/sysmacros.h>
368329232eSGordon Ross #include <sys/stropts.h>
378329232eSGordon Ross #include <sys/stream.h>
388329232eSGordon Ross #include <sys/strsubr.h>
398329232eSGordon Ross #include <sys/strsun.h>
408329232eSGordon Ross #include <sys/conf.h>
418329232eSGordon Ross #include <sys/debug.h>
428329232eSGordon Ross #include <sys/cmn_err.h>
438329232eSGordon Ross #include <sys/kmem.h>
448329232eSGordon Ross #include <sys/atomic.h>
458329232eSGordon Ross #include <sys/errno.h>
468329232eSGordon Ross #include <sys/vtrace.h>
478329232eSGordon Ross #include <sys/ftrace.h>
488329232eSGordon Ross #include <sys/ontrap.h>
498329232eSGordon Ross #include <sys/sdt.h>
508329232eSGordon Ross #include <sys/strft.h>
518329232eSGordon Ross
528329232eSGordon Ross /*
538329232eSGordon Ross * This file contains selected functions from io/stream.c
548329232eSGordon Ross * needed by this library, mostly unmodified.
558329232eSGordon Ross */
568329232eSGordon Ross
578329232eSGordon Ross /*
588329232eSGordon Ross * STREAMS message allocator: principles of operation
598329232eSGordon Ross * (See usr/src/uts/common/io/stream.c)
608329232eSGordon Ross */
618329232eSGordon Ross #define DBLK_MAX_CACHE 73728
628329232eSGordon Ross #define DBLK_CACHE_ALIGN 64
638329232eSGordon Ross #define DBLK_MIN_SIZE 8
648329232eSGordon Ross #define DBLK_SIZE_SHIFT 3
658329232eSGordon Ross
668329232eSGordon Ross #ifdef _BIG_ENDIAN
678329232eSGordon Ross #define DBLK_RTFU_SHIFT(field) \
688329232eSGordon Ross (8 * (&((dblk_t *)0)->db_struioflag - &((dblk_t *)0)->field))
698329232eSGordon Ross #else
708329232eSGordon Ross #define DBLK_RTFU_SHIFT(field) \
718329232eSGordon Ross (8 * (&((dblk_t *)0)->field - &((dblk_t *)0)->db_ref))
728329232eSGordon Ross #endif
738329232eSGordon Ross
748329232eSGordon Ross #define DBLK_RTFU(ref, type, flags, uioflag) \
758329232eSGordon Ross (((ref) << DBLK_RTFU_SHIFT(db_ref)) | \
768329232eSGordon Ross ((type) << DBLK_RTFU_SHIFT(db_type)) | \
778329232eSGordon Ross (((flags) | (ref - 1)) << DBLK_RTFU_SHIFT(db_flags)) | \
788329232eSGordon Ross ((uioflag) << DBLK_RTFU_SHIFT(db_struioflag)))
798329232eSGordon Ross #define DBLK_RTFU_REF_MASK (DBLK_REFMAX << DBLK_RTFU_SHIFT(db_ref))
808329232eSGordon Ross #define DBLK_RTFU_WORD(dbp) (*((uint32_t *)&(dbp)->db_ref))
818329232eSGordon Ross #define MBLK_BAND_FLAG_WORD(mp) (*((uint32_t *)&(mp)->b_band))
828329232eSGordon Ross
838329232eSGordon Ross static size_t dblk_sizes[] = {
848329232eSGordon Ross #ifdef _LP64
858329232eSGordon Ross 16, 80, 144, 208, 272, 336, 528, 1040, 1488, 1936, 2576, 3856,
868329232eSGordon Ross 8192, 12048, 16384, 20240, 24576, 28432, 32768, 36624,
878329232eSGordon Ross 40960, 44816, 49152, 53008, 57344, 61200, 65536, 69392,
888329232eSGordon Ross #else
898329232eSGordon Ross 64, 128, 320, 576, 1088, 1536, 1984, 2624, 3904,
908329232eSGordon Ross 8192, 12096, 16384, 20288, 24576, 28480, 32768, 36672,
918329232eSGordon Ross 40960, 44864, 49152, 53056, 57344, 61248, 65536, 69440,
928329232eSGordon Ross #endif
938329232eSGordon Ross DBLK_MAX_CACHE, 0
948329232eSGordon Ross };
958329232eSGordon Ross
968329232eSGordon Ross static struct kmem_cache *dblk_cache[DBLK_MAX_CACHE / DBLK_MIN_SIZE];
978329232eSGordon Ross static struct kmem_cache *mblk_cache;
988329232eSGordon Ross static struct kmem_cache *dblk_esb_cache;
998329232eSGordon Ross
1008329232eSGordon Ross static void dblk_lastfree(mblk_t *mp, dblk_t *dbp);
1018329232eSGordon Ross static mblk_t *allocb_oversize(size_t size, int flags);
1028329232eSGordon Ross static int allocb_tryhard_fails;
1038329232eSGordon Ross static void frnop_func(void *arg);
1048329232eSGordon Ross frtn_t frnop = { frnop_func };
1058329232eSGordon Ross static void bcache_dblk_lastfree(mblk_t *mp, dblk_t *dbp);
1068329232eSGordon Ross
1078329232eSGordon Ross /*
1088329232eSGordon Ross * Patchable mblk/dblk kmem_cache flags.
1098329232eSGordon Ross */
1108329232eSGordon Ross int dblk_kmem_flags = 0;
1118329232eSGordon Ross int mblk_kmem_flags = 0;
1128329232eSGordon Ross
1138329232eSGordon Ross static int
dblk_constructor(void * buf,void * cdrarg,int kmflags)1148329232eSGordon Ross dblk_constructor(void *buf, void *cdrarg, int kmflags)
1158329232eSGordon Ross {
1168329232eSGordon Ross dblk_t *dbp = buf;
1178329232eSGordon Ross ssize_t msg_size = (ssize_t)cdrarg;
1188329232eSGordon Ross size_t index;
1198329232eSGordon Ross
1208329232eSGordon Ross ASSERT(msg_size != 0);
1218329232eSGordon Ross
1228329232eSGordon Ross index = (msg_size - 1) >> DBLK_SIZE_SHIFT;
1238329232eSGordon Ross
1248329232eSGordon Ross ASSERT(index < (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT));
1258329232eSGordon Ross
1268329232eSGordon Ross if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
1278329232eSGordon Ross return (-1);
1288329232eSGordon Ross if ((msg_size & PAGEOFFSET) == 0) {
1298329232eSGordon Ross dbp->db_base = kmem_alloc(msg_size, kmflags);
1308329232eSGordon Ross if (dbp->db_base == NULL) {
1318329232eSGordon Ross kmem_cache_free(mblk_cache, dbp->db_mblk);
1328329232eSGordon Ross return (-1);
1338329232eSGordon Ross }
1348329232eSGordon Ross } else {
1358329232eSGordon Ross dbp->db_base = (unsigned char *)&dbp[1];
1368329232eSGordon Ross }
1378329232eSGordon Ross
1388329232eSGordon Ross dbp->db_mblk->b_datap = dbp;
1398329232eSGordon Ross dbp->db_cache = dblk_cache[index];
1408329232eSGordon Ross dbp->db_lim = dbp->db_base + msg_size;
1418329232eSGordon Ross dbp->db_free = dbp->db_lastfree = dblk_lastfree;
1428329232eSGordon Ross dbp->db_frtnp = NULL;
1438329232eSGordon Ross dbp->db_fthdr = NULL;
1448329232eSGordon Ross dbp->db_credp = NULL;
1458329232eSGordon Ross dbp->db_cpid = -1;
1468329232eSGordon Ross dbp->db_struioflag = 0;
1478329232eSGordon Ross dbp->db_struioun.cksum.flags = 0;
1488329232eSGordon Ross return (0);
1498329232eSGordon Ross }
1508329232eSGordon Ross
1518329232eSGordon Ross /*ARGSUSED*/
1528329232eSGordon Ross static int
dblk_esb_constructor(void * buf,void * cdrarg,int kmflags)1538329232eSGordon Ross dblk_esb_constructor(void *buf, void *cdrarg, int kmflags)
1548329232eSGordon Ross {
1558329232eSGordon Ross dblk_t *dbp = buf;
1568329232eSGordon Ross
1578329232eSGordon Ross if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
1588329232eSGordon Ross return (-1);
1598329232eSGordon Ross dbp->db_mblk->b_datap = dbp;
1608329232eSGordon Ross dbp->db_cache = dblk_esb_cache;
1618329232eSGordon Ross dbp->db_fthdr = NULL;
1628329232eSGordon Ross dbp->db_credp = NULL;
1638329232eSGordon Ross dbp->db_cpid = -1;
1648329232eSGordon Ross dbp->db_struioflag = 0;
1658329232eSGordon Ross dbp->db_struioun.cksum.flags = 0;
1668329232eSGordon Ross return (0);
1678329232eSGordon Ross }
1688329232eSGordon Ross
1698329232eSGordon Ross static int
bcache_dblk_constructor(void * buf,void * cdrarg,int kmflags)1708329232eSGordon Ross bcache_dblk_constructor(void *buf, void *cdrarg, int kmflags)
1718329232eSGordon Ross {
1728329232eSGordon Ross dblk_t *dbp = buf;
1738329232eSGordon Ross bcache_t *bcp = cdrarg;
1748329232eSGordon Ross
1758329232eSGordon Ross if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
1768329232eSGordon Ross return (-1);
1778329232eSGordon Ross
1788329232eSGordon Ross dbp->db_base = kmem_cache_alloc(bcp->buffer_cache, kmflags);
1798329232eSGordon Ross if (dbp->db_base == NULL) {
1808329232eSGordon Ross kmem_cache_free(mblk_cache, dbp->db_mblk);
1818329232eSGordon Ross return (-1);
1828329232eSGordon Ross }
1838329232eSGordon Ross
1848329232eSGordon Ross dbp->db_mblk->b_datap = dbp;
1858329232eSGordon Ross dbp->db_cache = (void *)bcp;
1868329232eSGordon Ross dbp->db_lim = dbp->db_base + bcp->size;
1878329232eSGordon Ross dbp->db_free = dbp->db_lastfree = bcache_dblk_lastfree;
1888329232eSGordon Ross dbp->db_frtnp = NULL;
1898329232eSGordon Ross dbp->db_fthdr = NULL;
1908329232eSGordon Ross dbp->db_credp = NULL;
1918329232eSGordon Ross dbp->db_cpid = -1;
1928329232eSGordon Ross dbp->db_struioflag = 0;
1938329232eSGordon Ross dbp->db_struioun.cksum.flags = 0;
1948329232eSGordon Ross return (0);
1958329232eSGordon Ross }
1968329232eSGordon Ross
1978329232eSGordon Ross /*ARGSUSED*/
1988329232eSGordon Ross static void
dblk_destructor(void * buf,void * cdrarg)1998329232eSGordon Ross dblk_destructor(void *buf, void *cdrarg)
2008329232eSGordon Ross {
2018329232eSGordon Ross dblk_t *dbp = buf;
2028329232eSGordon Ross ssize_t msg_size = (ssize_t)cdrarg;
2038329232eSGordon Ross
2048329232eSGordon Ross ASSERT(dbp->db_mblk->b_datap == dbp);
2058329232eSGordon Ross ASSERT(msg_size != 0);
2068329232eSGordon Ross ASSERT(dbp->db_struioflag == 0);
2078329232eSGordon Ross ASSERT(dbp->db_struioun.cksum.flags == 0);
2088329232eSGordon Ross
2098329232eSGordon Ross if ((msg_size & PAGEOFFSET) == 0) {
2108329232eSGordon Ross kmem_free(dbp->db_base, msg_size);
2118329232eSGordon Ross }
2128329232eSGordon Ross
2138329232eSGordon Ross kmem_cache_free(mblk_cache, dbp->db_mblk);
2148329232eSGordon Ross }
2158329232eSGordon Ross
2168329232eSGordon Ross static void
bcache_dblk_destructor(void * buf,void * cdrarg)2178329232eSGordon Ross bcache_dblk_destructor(void *buf, void *cdrarg)
2188329232eSGordon Ross {
2198329232eSGordon Ross dblk_t *dbp = buf;
2208329232eSGordon Ross bcache_t *bcp = cdrarg;
2218329232eSGordon Ross
2228329232eSGordon Ross kmem_cache_free(bcp->buffer_cache, dbp->db_base);
2238329232eSGordon Ross
2248329232eSGordon Ross ASSERT(dbp->db_mblk->b_datap == dbp);
2258329232eSGordon Ross ASSERT(dbp->db_struioflag == 0);
2268329232eSGordon Ross ASSERT(dbp->db_struioun.cksum.flags == 0);
2278329232eSGordon Ross
2288329232eSGordon Ross kmem_cache_free(mblk_cache, dbp->db_mblk);
2298329232eSGordon Ross }
2308329232eSGordon Ross
2318329232eSGordon Ross /* Needed in the ASSERT below */
2328329232eSGordon Ross #ifdef DEBUG
2338329232eSGordon Ross #ifdef _KERNEL
2348329232eSGordon Ross #define KMEM_SLAB_T_SZ sizeof (kmem_slab_t)
2358329232eSGordon Ross #else /* _KERNEL */
2368329232eSGordon Ross #define KMEM_SLAB_T_SZ 64 /* fakekernel */
2378329232eSGordon Ross #endif /* _KERNEL */
2388329232eSGordon Ross #endif /* DEBUG */
2398329232eSGordon Ross
2408329232eSGordon Ross void
streams_msg_init(void)2418329232eSGordon Ross streams_msg_init(void)
2428329232eSGordon Ross {
2438329232eSGordon Ross char name[40];
2448329232eSGordon Ross size_t size;
2458329232eSGordon Ross size_t lastsize = DBLK_MIN_SIZE;
2468329232eSGordon Ross size_t *sizep;
2478329232eSGordon Ross struct kmem_cache *cp;
2488329232eSGordon Ross size_t tot_size;
2498329232eSGordon Ross int offset;
2508329232eSGordon Ross
2518329232eSGordon Ross mblk_cache = kmem_cache_create("streams_mblk", sizeof (mblk_t), 32,
2528329232eSGordon Ross NULL, NULL, NULL, NULL, NULL, mblk_kmem_flags);
2538329232eSGordon Ross
2548329232eSGordon Ross for (sizep = dblk_sizes; (size = *sizep) != 0; sizep++) {
2558329232eSGordon Ross
2568329232eSGordon Ross if ((offset = (size & PAGEOFFSET)) != 0) {
2578329232eSGordon Ross /*
2588329232eSGordon Ross * We are in the middle of a page, dblk should
2598329232eSGordon Ross * be allocated on the same page
2608329232eSGordon Ross */
2618329232eSGordon Ross tot_size = size + sizeof (dblk_t);
2628329232eSGordon Ross ASSERT((offset + sizeof (dblk_t) + KMEM_SLAB_T_SZ)
2638329232eSGordon Ross < PAGESIZE);
2648329232eSGordon Ross ASSERT((tot_size & (DBLK_CACHE_ALIGN - 1)) == 0);
2658329232eSGordon Ross
2668329232eSGordon Ross } else {
2678329232eSGordon Ross
2688329232eSGordon Ross /*
2698329232eSGordon Ross * buf size is multiple of page size, dblk and
2708329232eSGordon Ross * buffer are allocated separately.
2718329232eSGordon Ross */
2728329232eSGordon Ross
2738329232eSGordon Ross ASSERT((size & (DBLK_CACHE_ALIGN - 1)) == 0);
2748329232eSGordon Ross tot_size = sizeof (dblk_t);
2758329232eSGordon Ross }
2768329232eSGordon Ross
2778329232eSGordon Ross (void) sprintf(name, "streams_dblk_%ld", (long)size);
2788329232eSGordon Ross cp = kmem_cache_create(name, tot_size, DBLK_CACHE_ALIGN,
2798329232eSGordon Ross dblk_constructor, dblk_destructor, NULL, (void *)(size),
2808329232eSGordon Ross NULL, dblk_kmem_flags);
2818329232eSGordon Ross
2828329232eSGordon Ross while (lastsize <= size) {
2838329232eSGordon Ross dblk_cache[(lastsize - 1) >> DBLK_SIZE_SHIFT] = cp;
2848329232eSGordon Ross lastsize += DBLK_MIN_SIZE;
2858329232eSGordon Ross }
2868329232eSGordon Ross }
2878329232eSGordon Ross
2888329232eSGordon Ross dblk_esb_cache = kmem_cache_create("streams_dblk_esb", sizeof (dblk_t),
2898329232eSGordon Ross DBLK_CACHE_ALIGN, dblk_esb_constructor, dblk_destructor, NULL,
2908329232eSGordon Ross (void *)sizeof (dblk_t), NULL, dblk_kmem_flags);
2918329232eSGordon Ross
292*9b664393SGarrett D'Amore /* fthdr_cache, ftblk_cache, ... */
2938329232eSGordon Ross }
2948329232eSGordon Ross
2958329232eSGordon Ross /*ARGSUSED*/
2968329232eSGordon Ross mblk_t *
allocb(size_t size,uint_t pri)2978329232eSGordon Ross allocb(size_t size, uint_t pri)
2988329232eSGordon Ross {
2998329232eSGordon Ross dblk_t *dbp;
3008329232eSGordon Ross mblk_t *mp;
3018329232eSGordon Ross size_t index;
3028329232eSGordon Ross
3038329232eSGordon Ross index = (size - 1) >> DBLK_SIZE_SHIFT;
3048329232eSGordon Ross
3058329232eSGordon Ross if (index >= (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT)) {
3068329232eSGordon Ross if (size != 0) {
3078329232eSGordon Ross mp = allocb_oversize(size, KM_NOSLEEP);
3088329232eSGordon Ross goto out;
3098329232eSGordon Ross }
3108329232eSGordon Ross index = 0;
3118329232eSGordon Ross }
3128329232eSGordon Ross
3138329232eSGordon Ross if ((dbp = kmem_cache_alloc(dblk_cache[index], KM_NOSLEEP)) == NULL) {
3148329232eSGordon Ross mp = NULL;
3158329232eSGordon Ross goto out;
3168329232eSGordon Ross }
3178329232eSGordon Ross
3188329232eSGordon Ross mp = dbp->db_mblk;
3198329232eSGordon Ross DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
3208329232eSGordon Ross mp->b_next = mp->b_prev = mp->b_cont = NULL;
3218329232eSGordon Ross mp->b_rptr = mp->b_wptr = dbp->db_base;
3228329232eSGordon Ross mp->b_queue = NULL;
3238329232eSGordon Ross MBLK_BAND_FLAG_WORD(mp) = 0;
3248329232eSGordon Ross STR_FTALLOC(&dbp->db_fthdr, FTEV_ALLOCB, size);
3258329232eSGordon Ross out:
3268329232eSGordon Ross FTRACE_1("allocb(): mp=0x%p", (uintptr_t)mp);
3278329232eSGordon Ross
3288329232eSGordon Ross return (mp);
3298329232eSGordon Ross }
3308329232eSGordon Ross
3318329232eSGordon Ross /*
3328329232eSGordon Ross * Allocate an mblk taking db_credp and db_cpid from the template.
3338329232eSGordon Ross * Allow the cred to be NULL.
3348329232eSGordon Ross */
3358329232eSGordon Ross mblk_t *
allocb_tmpl(size_t size,const mblk_t * tmpl)3368329232eSGordon Ross allocb_tmpl(size_t size, const mblk_t *tmpl)
3378329232eSGordon Ross {
3388329232eSGordon Ross mblk_t *mp = allocb(size, 0);
3398329232eSGordon Ross
3408329232eSGordon Ross if (mp != NULL) {
3418329232eSGordon Ross dblk_t *src = tmpl->b_datap;
3428329232eSGordon Ross dblk_t *dst = mp->b_datap;
3438329232eSGordon Ross cred_t *cr;
3448329232eSGordon Ross pid_t cpid;
3458329232eSGordon Ross
3468329232eSGordon Ross cr = msg_getcred(tmpl, &cpid);
3478329232eSGordon Ross if (cr != NULL)
3488329232eSGordon Ross crhold(dst->db_credp = cr);
3498329232eSGordon Ross dst->db_cpid = cpid;
3508329232eSGordon Ross dst->db_type = src->db_type;
3518329232eSGordon Ross }
3528329232eSGordon Ross return (mp);
3538329232eSGordon Ross }
3548329232eSGordon Ross
3558329232eSGordon Ross mblk_t *
allocb_cred(size_t size,cred_t * cr,pid_t cpid)3568329232eSGordon Ross allocb_cred(size_t size, cred_t *cr, pid_t cpid)
3578329232eSGordon Ross {
3588329232eSGordon Ross mblk_t *mp = allocb(size, 0);
3598329232eSGordon Ross
3608329232eSGordon Ross ASSERT(cr != NULL);
3618329232eSGordon Ross if (mp != NULL) {
3628329232eSGordon Ross dblk_t *dbp = mp->b_datap;
3638329232eSGordon Ross
3648329232eSGordon Ross crhold(dbp->db_credp = cr);
3658329232eSGordon Ross dbp->db_cpid = cpid;
3668329232eSGordon Ross }
3678329232eSGordon Ross return (mp);
3688329232eSGordon Ross }
3698329232eSGordon Ross
3708329232eSGordon Ross mblk_t *
allocb_cred_wait(size_t size,uint_t flags,int * error,cred_t * cr,pid_t cpid)3718329232eSGordon Ross allocb_cred_wait(size_t size, uint_t flags, int *error, cred_t *cr, pid_t cpid)
3728329232eSGordon Ross {
3738329232eSGordon Ross mblk_t *mp = allocb_wait(size, 0, flags, error);
3748329232eSGordon Ross
3758329232eSGordon Ross ASSERT(cr != NULL);
3768329232eSGordon Ross if (mp != NULL) {
3778329232eSGordon Ross dblk_t *dbp = mp->b_datap;
3788329232eSGordon Ross
3798329232eSGordon Ross crhold(dbp->db_credp = cr);
3808329232eSGordon Ross dbp->db_cpid = cpid;
3818329232eSGordon Ross }
3828329232eSGordon Ross
3838329232eSGordon Ross return (mp);
3848329232eSGordon Ross }
3858329232eSGordon Ross
3868329232eSGordon Ross /*
3878329232eSGordon Ross * Extract the db_cred (and optionally db_cpid) from a message.
3888329232eSGordon Ross * We find the first mblk which has a non-NULL db_cred and use that.
3898329232eSGordon Ross * If none found we return NULL.
3908329232eSGordon Ross * Does NOT get a hold on the cred.
3918329232eSGordon Ross */
3928329232eSGordon Ross cred_t *
msg_getcred(const mblk_t * mp,pid_t * cpidp)3938329232eSGordon Ross msg_getcred(const mblk_t *mp, pid_t *cpidp)
3948329232eSGordon Ross {
3958329232eSGordon Ross cred_t *cr = NULL;
3968329232eSGordon Ross
3978329232eSGordon Ross while (mp != NULL) {
3988329232eSGordon Ross dblk_t *dbp = mp->b_datap;
3998329232eSGordon Ross
4008329232eSGordon Ross cr = dbp->db_credp;
4018329232eSGordon Ross if (cr == NULL) {
4028329232eSGordon Ross mp = mp->b_cont;
4038329232eSGordon Ross continue;
4048329232eSGordon Ross }
4058329232eSGordon Ross if (cpidp != NULL)
4068329232eSGordon Ross *cpidp = dbp->db_cpid;
4078329232eSGordon Ross
4088329232eSGordon Ross /* DEBUG check for only one db_credp */
4098329232eSGordon Ross return (cr);
4108329232eSGordon Ross }
4118329232eSGordon Ross if (cpidp != NULL)
4128329232eSGordon Ross *cpidp = NOPID;
4138329232eSGordon Ross return (NULL);
4148329232eSGordon Ross }
4158329232eSGordon Ross
4168329232eSGordon Ross /*
4178329232eSGordon Ross * Variant of msg_getcred which, when a cred is found
4188329232eSGordon Ross * 1. Returns with a hold on the cred
4198329232eSGordon Ross * 2. Clears the first cred in the mblk.
4208329232eSGordon Ross * This is more efficient to use than a msg_getcred() + crhold() when
4218329232eSGordon Ross * the message is freed after the cred has been extracted.
4228329232eSGordon Ross *
4238329232eSGordon Ross * The caller is responsible for ensuring that there is no other reference
4248329232eSGordon Ross * on the message since db_credp can not be cleared when there are other
4258329232eSGordon Ross * references.
4268329232eSGordon Ross */
4278329232eSGordon Ross cred_t *
msg_extractcred(mblk_t * mp,pid_t * cpidp)4288329232eSGordon Ross msg_extractcred(mblk_t *mp, pid_t *cpidp)
4298329232eSGordon Ross {
4308329232eSGordon Ross cred_t *cr = NULL;
4318329232eSGordon Ross
4328329232eSGordon Ross while (mp != NULL) {
4338329232eSGordon Ross dblk_t *dbp = mp->b_datap;
4348329232eSGordon Ross
4358329232eSGordon Ross cr = dbp->db_credp;
4368329232eSGordon Ross if (cr == NULL) {
4378329232eSGordon Ross mp = mp->b_cont;
4388329232eSGordon Ross continue;
4398329232eSGordon Ross }
4408329232eSGordon Ross ASSERT(dbp->db_ref == 1);
4418329232eSGordon Ross dbp->db_credp = NULL;
4428329232eSGordon Ross if (cpidp != NULL)
4438329232eSGordon Ross *cpidp = dbp->db_cpid;
4448329232eSGordon Ross
4458329232eSGordon Ross /* DEBUG check for only one db_credp */
4468329232eSGordon Ross return (cr);
4478329232eSGordon Ross }
4488329232eSGordon Ross return (NULL);
4498329232eSGordon Ross }
4508329232eSGordon Ross
4518329232eSGordon Ross /* _KERNEL msg_getlabel() */
4528329232eSGordon Ross
4538329232eSGordon Ross void
freeb(mblk_t * mp)4548329232eSGordon Ross freeb(mblk_t *mp)
4558329232eSGordon Ross {
4568329232eSGordon Ross dblk_t *dbp = mp->b_datap;
4578329232eSGordon Ross
4588329232eSGordon Ross ASSERT(dbp->db_ref > 0);
4598329232eSGordon Ross ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
4608329232eSGordon Ross FTRACE_1("freeb(): mp=0x%lx", (uintptr_t)mp);
4618329232eSGordon Ross
4628329232eSGordon Ross STR_FTEVENT_MBLK(mp, caller(), FTEV_FREEB, dbp->db_ref);
4638329232eSGordon Ross
4648329232eSGordon Ross dbp->db_free(mp, dbp);
4658329232eSGordon Ross }
4668329232eSGordon Ross
4678329232eSGordon Ross void
freemsg(mblk_t * mp)4688329232eSGordon Ross freemsg(mblk_t *mp)
4698329232eSGordon Ross {
4708329232eSGordon Ross FTRACE_1("freemsg(): mp=0x%lx", (uintptr_t)mp);
4718329232eSGordon Ross while (mp) {
4728329232eSGordon Ross dblk_t *dbp = mp->b_datap;
4738329232eSGordon Ross mblk_t *mp_cont = mp->b_cont;
4748329232eSGordon Ross
4758329232eSGordon Ross ASSERT(dbp->db_ref > 0);
4768329232eSGordon Ross ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
4778329232eSGordon Ross
4788329232eSGordon Ross STR_FTEVENT_MBLK(mp, caller(), FTEV_FREEB, dbp->db_ref);
4798329232eSGordon Ross
4808329232eSGordon Ross dbp->db_free(mp, dbp);
4818329232eSGordon Ross mp = mp_cont;
4828329232eSGordon Ross }
4838329232eSGordon Ross }
4848329232eSGordon Ross
4858329232eSGordon Ross /*
4868329232eSGordon Ross * Reallocate a block for another use. Try hard to use the old block.
4878329232eSGordon Ross * If the old data is wanted (copy), leave b_wptr at the end of the data,
4888329232eSGordon Ross * otherwise return b_wptr = b_rptr.
4898329232eSGordon Ross *
4908329232eSGordon Ross * This routine is private and unstable.
4918329232eSGordon Ross */
4928329232eSGordon Ross mblk_t *
reallocb(mblk_t * mp,size_t size,uint_t copy)4938329232eSGordon Ross reallocb(mblk_t *mp, size_t size, uint_t copy)
4948329232eSGordon Ross {
4958329232eSGordon Ross mblk_t *mp1;
4968329232eSGordon Ross unsigned char *old_rptr;
4978329232eSGordon Ross ptrdiff_t cur_size;
4988329232eSGordon Ross
4998329232eSGordon Ross if (mp == NULL)
5008329232eSGordon Ross return (allocb(size, BPRI_HI));
5018329232eSGordon Ross
5028329232eSGordon Ross cur_size = mp->b_wptr - mp->b_rptr;
5038329232eSGordon Ross old_rptr = mp->b_rptr;
5048329232eSGordon Ross
5058329232eSGordon Ross ASSERT(mp->b_datap->db_ref != 0);
5068329232eSGordon Ross
5078329232eSGordon Ross if (mp->b_datap->db_ref == 1 && MBLKSIZE(mp) >= size) {
5088329232eSGordon Ross /*
5098329232eSGordon Ross * If the data is wanted and it will fit where it is, no
5108329232eSGordon Ross * work is required.
5118329232eSGordon Ross */
5128329232eSGordon Ross if (copy && mp->b_datap->db_lim - mp->b_rptr >= size)
5138329232eSGordon Ross return (mp);
5148329232eSGordon Ross
5158329232eSGordon Ross mp->b_wptr = mp->b_rptr = mp->b_datap->db_base;
5168329232eSGordon Ross mp1 = mp;
5178329232eSGordon Ross } else if ((mp1 = allocb_tmpl(size, mp)) != NULL) {
5188329232eSGordon Ross /* XXX other mp state could be copied too, db_flags ... ? */
5198329232eSGordon Ross mp1->b_cont = mp->b_cont;
5208329232eSGordon Ross } else {
5218329232eSGordon Ross return (NULL);
5228329232eSGordon Ross }
5238329232eSGordon Ross
5248329232eSGordon Ross if (copy) {
5258329232eSGordon Ross bcopy(old_rptr, mp1->b_rptr, cur_size);
5268329232eSGordon Ross mp1->b_wptr = mp1->b_rptr + cur_size;
5278329232eSGordon Ross }
5288329232eSGordon Ross
5298329232eSGordon Ross if (mp != mp1)
5308329232eSGordon Ross freeb(mp);
5318329232eSGordon Ross
5328329232eSGordon Ross return (mp1);
5338329232eSGordon Ross }
5348329232eSGordon Ross
5358329232eSGordon Ross static void
dblk_lastfree(mblk_t * mp,dblk_t * dbp)5368329232eSGordon Ross dblk_lastfree(mblk_t *mp, dblk_t *dbp)
5378329232eSGordon Ross {
5388329232eSGordon Ross ASSERT(dbp->db_mblk == mp);
5398329232eSGordon Ross if (dbp->db_fthdr != NULL)
5408329232eSGordon Ross str_ftfree(dbp);
5418329232eSGordon Ross
5428329232eSGordon Ross /* set credp and projid to be 'unspecified' before returning to cache */
5438329232eSGordon Ross if (dbp->db_credp != NULL) {
5448329232eSGordon Ross crfree(dbp->db_credp);
5458329232eSGordon Ross dbp->db_credp = NULL;
5468329232eSGordon Ross }
5478329232eSGordon Ross dbp->db_cpid = -1;
5488329232eSGordon Ross
5498329232eSGordon Ross /* Reset the struioflag and the checksum flag fields */
5508329232eSGordon Ross dbp->db_struioflag = 0;
5518329232eSGordon Ross dbp->db_struioun.cksum.flags = 0;
5528329232eSGordon Ross
5538329232eSGordon Ross /* and the COOKED and/or UIOA flag(s) */
5548329232eSGordon Ross dbp->db_flags &= ~(DBLK_COOKED | DBLK_UIOA);
5558329232eSGordon Ross
5568329232eSGordon Ross kmem_cache_free(dbp->db_cache, dbp);
5578329232eSGordon Ross }
5588329232eSGordon Ross
5598329232eSGordon Ross static void
dblk_decref(mblk_t * mp,dblk_t * dbp)5608329232eSGordon Ross dblk_decref(mblk_t *mp, dblk_t *dbp)
5618329232eSGordon Ross {
5628329232eSGordon Ross if (dbp->db_ref != 1) {
5638329232eSGordon Ross uint32_t rtfu = atomic_add_32_nv(&DBLK_RTFU_WORD(dbp),
5648329232eSGordon Ross -(1 << DBLK_RTFU_SHIFT(db_ref)));
5658329232eSGordon Ross /*
5668329232eSGordon Ross * atomic_add_32_nv() just decremented db_ref, so we no longer
5678329232eSGordon Ross * have a reference to the dblk, which means another thread
5688329232eSGordon Ross * could free it. Therefore we cannot examine the dblk to
5698329232eSGordon Ross * determine whether ours was the last reference. Instead,
5708329232eSGordon Ross * we extract the new and minimum reference counts from rtfu.
5718329232eSGordon Ross * Note that all we're really saying is "if (ref != refmin)".
5728329232eSGordon Ross */
5738329232eSGordon Ross if (((rtfu >> DBLK_RTFU_SHIFT(db_ref)) & DBLK_REFMAX) !=
5748329232eSGordon Ross ((rtfu >> DBLK_RTFU_SHIFT(db_flags)) & DBLK_REFMIN)) {
5758329232eSGordon Ross kmem_cache_free(mblk_cache, mp);
5768329232eSGordon Ross return;
5778329232eSGordon Ross }
5788329232eSGordon Ross }
5798329232eSGordon Ross dbp->db_mblk = mp;
5808329232eSGordon Ross dbp->db_free = dbp->db_lastfree;
5818329232eSGordon Ross dbp->db_lastfree(mp, dbp);
5828329232eSGordon Ross }
5838329232eSGordon Ross
5848329232eSGordon Ross mblk_t *
dupb(mblk_t * mp)5858329232eSGordon Ross dupb(mblk_t *mp)
5868329232eSGordon Ross {
5878329232eSGordon Ross dblk_t *dbp = mp->b_datap;
5888329232eSGordon Ross mblk_t *new_mp;
5898329232eSGordon Ross uint32_t oldrtfu, newrtfu;
5908329232eSGordon Ross
5918329232eSGordon Ross if ((new_mp = kmem_cache_alloc(mblk_cache, KM_NOSLEEP)) == NULL)
5928329232eSGordon Ross goto out;
5938329232eSGordon Ross
5948329232eSGordon Ross new_mp->b_next = new_mp->b_prev = new_mp->b_cont = NULL;
5958329232eSGordon Ross new_mp->b_rptr = mp->b_rptr;
5968329232eSGordon Ross new_mp->b_wptr = mp->b_wptr;
5978329232eSGordon Ross new_mp->b_datap = dbp;
5988329232eSGordon Ross new_mp->b_queue = NULL;
5998329232eSGordon Ross MBLK_BAND_FLAG_WORD(new_mp) = MBLK_BAND_FLAG_WORD(mp);
6008329232eSGordon Ross
6018329232eSGordon Ross STR_FTEVENT_MBLK(mp, caller(), FTEV_DUPB, dbp->db_ref);
6028329232eSGordon Ross
6038329232eSGordon Ross dbp->db_free = dblk_decref;
6048329232eSGordon Ross do {
6058329232eSGordon Ross ASSERT(dbp->db_ref > 0);
6068329232eSGordon Ross oldrtfu = DBLK_RTFU_WORD(dbp);
6078329232eSGordon Ross newrtfu = oldrtfu + (1 << DBLK_RTFU_SHIFT(db_ref));
6088329232eSGordon Ross /*
6098329232eSGordon Ross * If db_ref is maxed out we can't dup this message anymore.
6108329232eSGordon Ross */
6118329232eSGordon Ross if ((oldrtfu & DBLK_RTFU_REF_MASK) == DBLK_RTFU_REF_MASK) {
6128329232eSGordon Ross kmem_cache_free(mblk_cache, new_mp);
6138329232eSGordon Ross new_mp = NULL;
6148329232eSGordon Ross goto out;
6158329232eSGordon Ross }
6168329232eSGordon Ross } while (atomic_cas_32(&DBLK_RTFU_WORD(dbp), oldrtfu, newrtfu) !=
6178329232eSGordon Ross oldrtfu);
6188329232eSGordon Ross
6198329232eSGordon Ross out:
6208329232eSGordon Ross FTRACE_1("dupb(): new_mp=0x%lx", (uintptr_t)new_mp);
6218329232eSGordon Ross return (new_mp);
6228329232eSGordon Ross }
6238329232eSGordon Ross
6248329232eSGordon Ross /*ARGSUSED*/
6258329232eSGordon Ross static void
frnop_func(void * arg)6268329232eSGordon Ross frnop_func(void *arg)
6278329232eSGordon Ross {
6288329232eSGordon Ross }
6298329232eSGordon Ross
6308329232eSGordon Ross /*
6318329232eSGordon Ross * Generic esballoc used to implement the four flavors: [d]esballoc[a].
6328329232eSGordon Ross * and allocb_oversize
6338329232eSGordon Ross */
6348329232eSGordon Ross static mblk_t *
gesballoc(unsigned char * base,size_t size,uint32_t db_rtfu,frtn_t * frp,void (* lastfree)(mblk_t *,dblk_t *),int kmflags)6358329232eSGordon Ross gesballoc(unsigned char *base, size_t size, uint32_t db_rtfu, frtn_t *frp,
636*9b664393SGarrett D'Amore void (*lastfree)(mblk_t *, dblk_t *), int kmflags)
6378329232eSGordon Ross {
6388329232eSGordon Ross dblk_t *dbp;
6398329232eSGordon Ross mblk_t *mp;
6408329232eSGordon Ross
6418329232eSGordon Ross ASSERT(base != NULL && frp != NULL);
6428329232eSGordon Ross
6438329232eSGordon Ross if ((dbp = kmem_cache_alloc(dblk_esb_cache, kmflags)) == NULL) {
6448329232eSGordon Ross mp = NULL;
6458329232eSGordon Ross goto out;
6468329232eSGordon Ross }
6478329232eSGordon Ross
6488329232eSGordon Ross mp = dbp->db_mblk;
6498329232eSGordon Ross dbp->db_base = base;
6508329232eSGordon Ross dbp->db_lim = base + size;
6518329232eSGordon Ross dbp->db_free = dbp->db_lastfree = lastfree;
6528329232eSGordon Ross dbp->db_frtnp = frp;
6538329232eSGordon Ross DBLK_RTFU_WORD(dbp) = db_rtfu;
6548329232eSGordon Ross mp->b_next = mp->b_prev = mp->b_cont = NULL;
6558329232eSGordon Ross mp->b_rptr = mp->b_wptr = base;
6568329232eSGordon Ross mp->b_queue = NULL;
6578329232eSGordon Ross MBLK_BAND_FLAG_WORD(mp) = 0;
6588329232eSGordon Ross
6598329232eSGordon Ross out:
6608329232eSGordon Ross FTRACE_1("gesballoc(): mp=0x%lx", (uintptr_t)mp);
6618329232eSGordon Ross return (mp);
6628329232eSGordon Ross }
6638329232eSGordon Ross
6648329232eSGordon Ross static void
bcache_dblk_lastfree(mblk_t * mp,dblk_t * dbp)6658329232eSGordon Ross bcache_dblk_lastfree(mblk_t *mp, dblk_t *dbp)
6668329232eSGordon Ross {
6678329232eSGordon Ross bcache_t *bcp = dbp->db_cache;
6688329232eSGordon Ross
6698329232eSGordon Ross ASSERT(dbp->db_mblk == mp);
6708329232eSGordon Ross if (dbp->db_fthdr != NULL)
6718329232eSGordon Ross str_ftfree(dbp);
6728329232eSGordon Ross
6738329232eSGordon Ross /* set credp and projid to be 'unspecified' before returning to cache */
6748329232eSGordon Ross if (dbp->db_credp != NULL) {
6758329232eSGordon Ross crfree(dbp->db_credp);
6768329232eSGordon Ross dbp->db_credp = NULL;
6778329232eSGordon Ross }
6788329232eSGordon Ross dbp->db_cpid = -1;
6798329232eSGordon Ross dbp->db_struioflag = 0;
6808329232eSGordon Ross dbp->db_struioun.cksum.flags = 0;
6818329232eSGordon Ross
6828329232eSGordon Ross mutex_enter(&bcp->mutex);
6838329232eSGordon Ross kmem_cache_free(bcp->dblk_cache, dbp);
6848329232eSGordon Ross bcp->alloc--;
6858329232eSGordon Ross
6868329232eSGordon Ross if (bcp->alloc == 0 && bcp->destroy != 0) {
6878329232eSGordon Ross kmem_cache_destroy(bcp->dblk_cache);
6888329232eSGordon Ross kmem_cache_destroy(bcp->buffer_cache);
6898329232eSGordon Ross mutex_exit(&bcp->mutex);
6908329232eSGordon Ross mutex_destroy(&bcp->mutex);
6918329232eSGordon Ross kmem_free(bcp, sizeof (bcache_t));
6928329232eSGordon Ross } else {
6938329232eSGordon Ross mutex_exit(&bcp->mutex);
6948329232eSGordon Ross }
6958329232eSGordon Ross }
6968329232eSGordon Ross
6978329232eSGordon Ross bcache_t *
bcache_create(char * name,size_t size,uint_t align)6988329232eSGordon Ross bcache_create(char *name, size_t size, uint_t align)
6998329232eSGordon Ross {
7008329232eSGordon Ross bcache_t *bcp;
7018329232eSGordon Ross char buffer[255];
7028329232eSGordon Ross
7038329232eSGordon Ross ASSERT((align & (align - 1)) == 0);
7048329232eSGordon Ross
7058329232eSGordon Ross if ((bcp = kmem_alloc(sizeof (bcache_t), KM_NOSLEEP)) == NULL)
7068329232eSGordon Ross return (NULL);
7078329232eSGordon Ross
7088329232eSGordon Ross bcp->size = size;
7098329232eSGordon Ross bcp->align = align;
7108329232eSGordon Ross bcp->alloc = 0;
7118329232eSGordon Ross bcp->destroy = 0;
7128329232eSGordon Ross
7138329232eSGordon Ross mutex_init(&bcp->mutex, NULL, MUTEX_DRIVER, NULL);
7148329232eSGordon Ross
7158329232eSGordon Ross (void) sprintf(buffer, "%s_buffer_cache", name);
7168329232eSGordon Ross bcp->buffer_cache = kmem_cache_create(buffer, size, align, NULL, NULL,
7178329232eSGordon Ross NULL, NULL, NULL, 0);
7188329232eSGordon Ross (void) sprintf(buffer, "%s_dblk_cache", name);
7198329232eSGordon Ross bcp->dblk_cache = kmem_cache_create(buffer, sizeof (dblk_t),
7208329232eSGordon Ross DBLK_CACHE_ALIGN, bcache_dblk_constructor, bcache_dblk_destructor,
7218329232eSGordon Ross NULL, (void *)bcp, NULL, 0);
7228329232eSGordon Ross
7238329232eSGordon Ross return (bcp);
7248329232eSGordon Ross }
7258329232eSGordon Ross
7268329232eSGordon Ross void
bcache_destroy(bcache_t * bcp)7278329232eSGordon Ross bcache_destroy(bcache_t *bcp)
7288329232eSGordon Ross {
7298329232eSGordon Ross ASSERT(bcp != NULL);
7308329232eSGordon Ross
7318329232eSGordon Ross mutex_enter(&bcp->mutex);
7328329232eSGordon Ross if (bcp->alloc == 0) {
7338329232eSGordon Ross kmem_cache_destroy(bcp->dblk_cache);
7348329232eSGordon Ross kmem_cache_destroy(bcp->buffer_cache);
7358329232eSGordon Ross mutex_exit(&bcp->mutex);
7368329232eSGordon Ross mutex_destroy(&bcp->mutex);
7378329232eSGordon Ross kmem_free(bcp, sizeof (bcache_t));
7388329232eSGordon Ross } else {
7398329232eSGordon Ross bcp->destroy++;
7408329232eSGordon Ross mutex_exit(&bcp->mutex);
7418329232eSGordon Ross }
7428329232eSGordon Ross }
7438329232eSGordon Ross
7448329232eSGordon Ross /*ARGSUSED*/
7458329232eSGordon Ross mblk_t *
bcache_allocb(bcache_t * bcp,uint_t pri)7468329232eSGordon Ross bcache_allocb(bcache_t *bcp, uint_t pri)
7478329232eSGordon Ross {
7488329232eSGordon Ross dblk_t *dbp;
7498329232eSGordon Ross mblk_t *mp = NULL;
7508329232eSGordon Ross
7518329232eSGordon Ross ASSERT(bcp != NULL);
7528329232eSGordon Ross
7538329232eSGordon Ross mutex_enter(&bcp->mutex);
7548329232eSGordon Ross if (bcp->destroy != 0) {
7558329232eSGordon Ross mutex_exit(&bcp->mutex);
7568329232eSGordon Ross goto out;
7578329232eSGordon Ross }
7588329232eSGordon Ross
7598329232eSGordon Ross if ((dbp = kmem_cache_alloc(bcp->dblk_cache, KM_NOSLEEP)) == NULL) {
7608329232eSGordon Ross mutex_exit(&bcp->mutex);
7618329232eSGordon Ross goto out;
7628329232eSGordon Ross }
7638329232eSGordon Ross bcp->alloc++;
7648329232eSGordon Ross mutex_exit(&bcp->mutex);
7658329232eSGordon Ross
7668329232eSGordon Ross ASSERT(((uintptr_t)(dbp->db_base) & (bcp->align - 1)) == 0);
7678329232eSGordon Ross
7688329232eSGordon Ross mp = dbp->db_mblk;
7698329232eSGordon Ross DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
7708329232eSGordon Ross mp->b_next = mp->b_prev = mp->b_cont = NULL;
7718329232eSGordon Ross mp->b_rptr = mp->b_wptr = dbp->db_base;
7728329232eSGordon Ross mp->b_queue = NULL;
7738329232eSGordon Ross MBLK_BAND_FLAG_WORD(mp) = 0;
7748329232eSGordon Ross STR_FTALLOC(&dbp->db_fthdr, FTEV_BCALLOCB, bcp->size);
7758329232eSGordon Ross out:
7768329232eSGordon Ross FTRACE_1("bcache_allocb(): mp=0x%p", (uintptr_t)mp);
7778329232eSGordon Ross
7788329232eSGordon Ross return (mp);
7798329232eSGordon Ross }
7808329232eSGordon Ross
7818329232eSGordon Ross static void
dblk_lastfree_oversize(mblk_t * mp,dblk_t * dbp)7828329232eSGordon Ross dblk_lastfree_oversize(mblk_t *mp, dblk_t *dbp)
7838329232eSGordon Ross {
7848329232eSGordon Ross ASSERT(dbp->db_mblk == mp);
7858329232eSGordon Ross if (dbp->db_fthdr != NULL)
7868329232eSGordon Ross str_ftfree(dbp);
7878329232eSGordon Ross
7888329232eSGordon Ross /* set credp and projid to be 'unspecified' before returning to cache */
7898329232eSGordon Ross if (dbp->db_credp != NULL) {
7908329232eSGordon Ross crfree(dbp->db_credp);
7918329232eSGordon Ross dbp->db_credp = NULL;
7928329232eSGordon Ross }
7938329232eSGordon Ross dbp->db_cpid = -1;
7948329232eSGordon Ross dbp->db_struioflag = 0;
7958329232eSGordon Ross dbp->db_struioun.cksum.flags = 0;
7968329232eSGordon Ross
7978329232eSGordon Ross kmem_free(dbp->db_base, dbp->db_lim - dbp->db_base);
7988329232eSGordon Ross kmem_cache_free(dbp->db_cache, dbp);
7998329232eSGordon Ross }
8008329232eSGordon Ross
8018329232eSGordon Ross static mblk_t *
allocb_oversize(size_t size,int kmflags)8028329232eSGordon Ross allocb_oversize(size_t size, int kmflags)
8038329232eSGordon Ross {
8048329232eSGordon Ross mblk_t *mp;
8058329232eSGordon Ross void *buf;
8068329232eSGordon Ross
8078329232eSGordon Ross size = P2ROUNDUP(size, DBLK_CACHE_ALIGN);
8088329232eSGordon Ross if ((buf = kmem_alloc(size, kmflags)) == NULL)
8098329232eSGordon Ross return (NULL);
8108329232eSGordon Ross if ((mp = gesballoc(buf, size, DBLK_RTFU(1, M_DATA, 0, 0),
8118329232eSGordon Ross &frnop, dblk_lastfree_oversize, kmflags)) == NULL)
8128329232eSGordon Ross kmem_free(buf, size);
8138329232eSGordon Ross
8148329232eSGordon Ross if (mp != NULL)
8158329232eSGordon Ross STR_FTALLOC(&DB_FTHDR(mp), FTEV_ALLOCBIG, size);
8168329232eSGordon Ross
8178329232eSGordon Ross return (mp);
8188329232eSGordon Ross }
8198329232eSGordon Ross
8208329232eSGordon Ross mblk_t *
allocb_tryhard(size_t target_size)8218329232eSGordon Ross allocb_tryhard(size_t target_size)
8228329232eSGordon Ross {
8238329232eSGordon Ross size_t size;
8248329232eSGordon Ross mblk_t *bp;
8258329232eSGordon Ross
8268329232eSGordon Ross for (size = target_size; size < target_size + 512;
8278329232eSGordon Ross size += DBLK_CACHE_ALIGN)
8288329232eSGordon Ross if ((bp = allocb(size, BPRI_HI)) != NULL)
8298329232eSGordon Ross return (bp);
8308329232eSGordon Ross allocb_tryhard_fails++;
8318329232eSGordon Ross return (NULL);
8328329232eSGordon Ross }
8338329232eSGordon Ross
8348329232eSGordon Ross /*
8358329232eSGordon Ross * This routine is consolidation private for STREAMS internal use
8368329232eSGordon Ross * This routine may only be called from sync routines (i.e., not
8378329232eSGordon Ross * from put or service procedures). It is located here (rather
8388329232eSGordon Ross * than strsubr.c) so that we don't have to expose all of the
8398329232eSGordon Ross * allocb() implementation details in header files.
8408329232eSGordon Ross */
8418329232eSGordon Ross mblk_t *
allocb_wait(size_t size,uint_t pri,uint_t flags,int * error)8428329232eSGordon Ross allocb_wait(size_t size, uint_t pri, uint_t flags, int *error)
8438329232eSGordon Ross {
8448329232eSGordon Ross dblk_t *dbp;
8458329232eSGordon Ross mblk_t *mp;
8468329232eSGordon Ross size_t index;
8478329232eSGordon Ross
8488329232eSGordon Ross index = (size -1) >> DBLK_SIZE_SHIFT;
8498329232eSGordon Ross
8508329232eSGordon Ross if (flags & STR_NOSIG) {
8518329232eSGordon Ross if (index >= (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT)) {
8528329232eSGordon Ross if (size != 0) {
8538329232eSGordon Ross mp = allocb_oversize(size, KM_SLEEP);
8548329232eSGordon Ross FTRACE_1("allocb_wait (NOSIG): mp=0x%lx",
8558329232eSGordon Ross (uintptr_t)mp);
8568329232eSGordon Ross return (mp);
8578329232eSGordon Ross }
8588329232eSGordon Ross index = 0;
8598329232eSGordon Ross }
8608329232eSGordon Ross
8618329232eSGordon Ross dbp = kmem_cache_alloc(dblk_cache[index], KM_SLEEP);
8628329232eSGordon Ross mp = dbp->db_mblk;
8638329232eSGordon Ross DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
8648329232eSGordon Ross mp->b_next = mp->b_prev = mp->b_cont = NULL;
8658329232eSGordon Ross mp->b_rptr = mp->b_wptr = dbp->db_base;
8668329232eSGordon Ross mp->b_queue = NULL;
8678329232eSGordon Ross MBLK_BAND_FLAG_WORD(mp) = 0;
8688329232eSGordon Ross STR_FTALLOC(&DB_FTHDR(mp), FTEV_ALLOCBW, size);
8698329232eSGordon Ross
8708329232eSGordon Ross FTRACE_1("allocb_wait (NOSIG): mp=0x%lx", (uintptr_t)mp);
8718329232eSGordon Ross
8728329232eSGordon Ross } else {
8738329232eSGordon Ross while ((mp = allocb(size, pri)) == NULL) {
8748329232eSGordon Ross if ((*error = strwaitbuf(size, BPRI_HI)) != 0)
8758329232eSGordon Ross return (NULL);
8768329232eSGordon Ross }
8778329232eSGordon Ross }
8788329232eSGordon Ross
8798329232eSGordon Ross return (mp);
8808329232eSGordon Ross }
8818329232eSGordon Ross
8828329232eSGordon Ross /*
8838329232eSGordon Ross * Call function 'func' with 'arg' when a class zero block can
8848329232eSGordon Ross * be allocated with priority 'pri'.
8858329232eSGordon Ross */
8868329232eSGordon Ross bufcall_id_t
esbbcall(uint_t pri,void (* func)(void *),void * arg)8878329232eSGordon Ross esbbcall(uint_t pri, void (*func)(void *), void *arg)
8888329232eSGordon Ross {
8898329232eSGordon Ross return (bufcall(1, pri, func, arg));
8908329232eSGordon Ross }
8918329232eSGordon Ross
8928329232eSGordon Ross /*
8938329232eSGordon Ross * Allocates an iocblk (M_IOCTL) block. Properly sets the credentials
8948329232eSGordon Ross * ioc_id, rval and error of the struct ioctl to set up an ioctl call.
8958329232eSGordon Ross * This provides consistency for all internal allocators of ioctl.
8968329232eSGordon Ross */
8978329232eSGordon Ross mblk_t *
mkiocb(uint_t cmd)8988329232eSGordon Ross mkiocb(uint_t cmd)
8998329232eSGordon Ross {
9008329232eSGordon Ross struct iocblk *ioc;
9018329232eSGordon Ross mblk_t *mp;
9028329232eSGordon Ross
9038329232eSGordon Ross /*
9048329232eSGordon Ross * Allocate enough space for any of the ioctl related messages.
9058329232eSGordon Ross */
9068329232eSGordon Ross if ((mp = allocb(sizeof (union ioctypes), BPRI_MED)) == NULL)
9078329232eSGordon Ross return (NULL);
9088329232eSGordon Ross
9098329232eSGordon Ross bzero(mp->b_rptr, sizeof (union ioctypes));
9108329232eSGordon Ross
9118329232eSGordon Ross /*
9128329232eSGordon Ross * Set the mblk_t information and ptrs correctly.
9138329232eSGordon Ross */
9148329232eSGordon Ross mp->b_wptr += sizeof (struct iocblk);
9158329232eSGordon Ross mp->b_datap->db_type = M_IOCTL;
9168329232eSGordon Ross
9178329232eSGordon Ross /*
9188329232eSGordon Ross * Fill in the fields.
9198329232eSGordon Ross */
9208329232eSGordon Ross ioc = (struct iocblk *)mp->b_rptr;
9218329232eSGordon Ross ioc->ioc_cmd = cmd;
9228329232eSGordon Ross ioc->ioc_cr = kcred;
9238329232eSGordon Ross ioc->ioc_id = getiocseqno();
9248329232eSGordon Ross ioc->ioc_flag = IOC_NATIVE;
9258329232eSGordon Ross return (mp);
9268329232eSGordon Ross }
9278329232eSGordon Ross
9288329232eSGordon Ross /*
9298329232eSGordon Ross * test if block of given size can be allocated with a request of
9308329232eSGordon Ross * the given priority.
9318329232eSGordon Ross * 'pri' is no longer used, but is retained for compatibility.
9328329232eSGordon Ross */
9338329232eSGordon Ross /* ARGSUSED */
9348329232eSGordon Ross int
testb(size_t size,uint_t pri)9358329232eSGordon Ross testb(size_t size, uint_t pri)
9368329232eSGordon Ross {
9378329232eSGordon Ross return ((size + sizeof (dblk_t)) <= kmem_avail());
9388329232eSGordon Ross }
9398329232eSGordon Ross
9408329232eSGordon Ross /* _KERNEL: bufcall, unbufcall */
9418329232eSGordon Ross
9428329232eSGordon Ross /*
9438329232eSGordon Ross * Duplicate a message block by block (uses dupb), returning
9448329232eSGordon Ross * a pointer to the duplicate message.
9458329232eSGordon Ross * Returns a non-NULL value only if the entire message
9468329232eSGordon Ross * was dup'd.
9478329232eSGordon Ross */
9488329232eSGordon Ross mblk_t *
dupmsg(mblk_t * bp)9498329232eSGordon Ross dupmsg(mblk_t *bp)
9508329232eSGordon Ross {
9518329232eSGordon Ross mblk_t *head, *nbp;
9528329232eSGordon Ross
9538329232eSGordon Ross if (!bp || !(nbp = head = dupb(bp)))
9548329232eSGordon Ross return (NULL);
9558329232eSGordon Ross
9568329232eSGordon Ross while (bp->b_cont) {
9578329232eSGordon Ross if (!(nbp->b_cont = dupb(bp->b_cont))) {
9588329232eSGordon Ross freemsg(head);
9598329232eSGordon Ross return (NULL);
9608329232eSGordon Ross }
9618329232eSGordon Ross nbp = nbp->b_cont;
9628329232eSGordon Ross bp = bp->b_cont;
9638329232eSGordon Ross }
9648329232eSGordon Ross return (head);
9658329232eSGordon Ross }
9668329232eSGordon Ross
9678329232eSGordon Ross #define DUPB_NOLOAN(bp) \
9688329232eSGordon Ross ((((bp)->b_datap->db_struioflag & STRUIO_ZC) != 0) ? \
9698329232eSGordon Ross copyb((bp)) : dupb((bp)))
9708329232eSGordon Ross
9718329232eSGordon Ross mblk_t *
dupmsg_noloan(mblk_t * bp)9728329232eSGordon Ross dupmsg_noloan(mblk_t *bp)
9738329232eSGordon Ross {
9748329232eSGordon Ross mblk_t *head, *nbp;
9758329232eSGordon Ross
9768329232eSGordon Ross if (bp == NULL || DB_TYPE(bp) != M_DATA ||
9778329232eSGordon Ross ((nbp = head = DUPB_NOLOAN(bp)) == NULL))
9788329232eSGordon Ross return (NULL);
9798329232eSGordon Ross
9808329232eSGordon Ross while (bp->b_cont) {
9818329232eSGordon Ross if ((nbp->b_cont = DUPB_NOLOAN(bp->b_cont)) == NULL) {
9828329232eSGordon Ross freemsg(head);
9838329232eSGordon Ross return (NULL);
9848329232eSGordon Ross }
9858329232eSGordon Ross nbp = nbp->b_cont;
9868329232eSGordon Ross bp = bp->b_cont;
9878329232eSGordon Ross }
9888329232eSGordon Ross return (head);
9898329232eSGordon Ross }
9908329232eSGordon Ross
9918329232eSGordon Ross /*
9928329232eSGordon Ross * Copy data from message and data block to newly allocated message and
9938329232eSGordon Ross * data block. Returns new message block pointer, or NULL if error.
9948329232eSGordon Ross * The alignment of rptr (w.r.t. word alignment) will be the same in the copy
9958329232eSGordon Ross * as in the original even when db_base is not word aligned. (bug 1052877)
9968329232eSGordon Ross */
9978329232eSGordon Ross mblk_t *
copyb(mblk_t * bp)9988329232eSGordon Ross copyb(mblk_t *bp)
9998329232eSGordon Ross {
10008329232eSGordon Ross mblk_t *nbp;
10018329232eSGordon Ross dblk_t *dp, *ndp;
10028329232eSGordon Ross uchar_t *base;
10038329232eSGordon Ross size_t size;
10048329232eSGordon Ross size_t unaligned;
10058329232eSGordon Ross
10068329232eSGordon Ross ASSERT(bp->b_wptr >= bp->b_rptr);
10078329232eSGordon Ross
10088329232eSGordon Ross dp = bp->b_datap;
10098329232eSGordon Ross if (dp->db_fthdr != NULL)
10108329232eSGordon Ross STR_FTEVENT_MBLK(bp, caller(), FTEV_COPYB, 0);
10118329232eSGordon Ross
10128329232eSGordon Ross size = dp->db_lim - dp->db_base;
10138329232eSGordon Ross unaligned = P2PHASE((uintptr_t)dp->db_base, sizeof (uint_t));
10148329232eSGordon Ross if ((nbp = allocb_tmpl(size + unaligned, bp)) == NULL)
10158329232eSGordon Ross return (NULL);
10168329232eSGordon Ross nbp->b_flag = bp->b_flag;
10178329232eSGordon Ross nbp->b_band = bp->b_band;
10188329232eSGordon Ross ndp = nbp->b_datap;
10198329232eSGordon Ross
10208329232eSGordon Ross /*
10218329232eSGordon Ross * Well, here is a potential issue. If we are trying to
10228329232eSGordon Ross * trace a flow, and we copy the message, we might lose
10238329232eSGordon Ross * information about where this message might have been.
10248329232eSGordon Ross * So we should inherit the FT data. On the other hand,
10258329232eSGordon Ross * a user might be interested only in alloc to free data.
10268329232eSGordon Ross * So I guess the real answer is to provide a tunable.
10278329232eSGordon Ross */
10288329232eSGordon Ross STR_FTEVENT_MBLK(nbp, caller(), FTEV_COPYB, 1);
10298329232eSGordon Ross
10308329232eSGordon Ross base = ndp->db_base + unaligned;
10318329232eSGordon Ross bcopy(dp->db_base, ndp->db_base + unaligned, size);
10328329232eSGordon Ross
10338329232eSGordon Ross nbp->b_rptr = base + (bp->b_rptr - dp->db_base);
10348329232eSGordon Ross nbp->b_wptr = nbp->b_rptr + MBLKL(bp);
10358329232eSGordon Ross
10368329232eSGordon Ross return (nbp);
10378329232eSGordon Ross }
10388329232eSGordon Ross
10398329232eSGordon Ross /*
10408329232eSGordon Ross * Copy data from message to newly allocated message using new
10418329232eSGordon Ross * data blocks. Returns a pointer to the new message, or NULL if error.
10428329232eSGordon Ross */
10438329232eSGordon Ross mblk_t *
copymsg(mblk_t * bp)10448329232eSGordon Ross copymsg(mblk_t *bp)
10458329232eSGordon Ross {
10468329232eSGordon Ross mblk_t *head, *nbp;
10478329232eSGordon Ross
10488329232eSGordon Ross if (!bp || !(nbp = head = copyb(bp)))
10498329232eSGordon Ross return (NULL);
10508329232eSGordon Ross
10518329232eSGordon Ross while (bp->b_cont) {
10528329232eSGordon Ross if (!(nbp->b_cont = copyb(bp->b_cont))) {
10538329232eSGordon Ross freemsg(head);
10548329232eSGordon Ross return (NULL);
10558329232eSGordon Ross }
10568329232eSGordon Ross nbp = nbp->b_cont;
10578329232eSGordon Ross bp = bp->b_cont;
10588329232eSGordon Ross }
10598329232eSGordon Ross return (head);
10608329232eSGordon Ross }
10618329232eSGordon Ross
10628329232eSGordon Ross /*
10638329232eSGordon Ross * link a message block to tail of message
10648329232eSGordon Ross */
10658329232eSGordon Ross void
linkb(mblk_t * mp,mblk_t * bp)10668329232eSGordon Ross linkb(mblk_t *mp, mblk_t *bp)
10678329232eSGordon Ross {
10688329232eSGordon Ross ASSERT(mp && bp);
10698329232eSGordon Ross
10708329232eSGordon Ross for (; mp->b_cont; mp = mp->b_cont)
10718329232eSGordon Ross ;
10728329232eSGordon Ross mp->b_cont = bp;
10738329232eSGordon Ross }
10748329232eSGordon Ross
10758329232eSGordon Ross /*
10768329232eSGordon Ross * unlink a message block from head of message
10778329232eSGordon Ross * return pointer to new message.
10788329232eSGordon Ross * NULL if message becomes empty.
10798329232eSGordon Ross */
10808329232eSGordon Ross mblk_t *
unlinkb(mblk_t * bp)10818329232eSGordon Ross unlinkb(mblk_t *bp)
10828329232eSGordon Ross {
10838329232eSGordon Ross mblk_t *bp1;
10848329232eSGordon Ross
10858329232eSGordon Ross bp1 = bp->b_cont;
10868329232eSGordon Ross bp->b_cont = NULL;
10878329232eSGordon Ross return (bp1);
10888329232eSGordon Ross }
10898329232eSGordon Ross
10908329232eSGordon Ross /*
10918329232eSGordon Ross * remove a message block "bp" from message "mp"
10928329232eSGordon Ross *
10938329232eSGordon Ross * Return pointer to new message or NULL if no message remains.
10948329232eSGordon Ross * Return -1 if bp is not found in message.
10958329232eSGordon Ross */
10968329232eSGordon Ross mblk_t *
rmvb(mblk_t * mp,mblk_t * bp)10978329232eSGordon Ross rmvb(mblk_t *mp, mblk_t *bp)
10988329232eSGordon Ross {
10998329232eSGordon Ross mblk_t *tmp;
11008329232eSGordon Ross mblk_t *lastp = NULL;
11018329232eSGordon Ross
11028329232eSGordon Ross ASSERT(mp && bp);
11038329232eSGordon Ross for (tmp = mp; tmp; tmp = tmp->b_cont) {
11048329232eSGordon Ross if (tmp == bp) {
11058329232eSGordon Ross if (lastp)
11068329232eSGordon Ross lastp->b_cont = tmp->b_cont;
11078329232eSGordon Ross else
11088329232eSGordon Ross mp = tmp->b_cont;
11098329232eSGordon Ross tmp->b_cont = NULL;
11108329232eSGordon Ross return (mp);
11118329232eSGordon Ross }
11128329232eSGordon Ross lastp = tmp;
11138329232eSGordon Ross }
11148329232eSGordon Ross return ((mblk_t *)-1);
11158329232eSGordon Ross }
11168329232eSGordon Ross
11178329232eSGordon Ross /*
11188329232eSGordon Ross * Concatenate and align first len bytes of common
11198329232eSGordon Ross * message type. Len == -1, means concat everything.
11208329232eSGordon Ross * Returns 1 on success, 0 on failure
11218329232eSGordon Ross * After the pullup, mp points to the pulled up data.
11228329232eSGordon Ross */
11238329232eSGordon Ross int
pullupmsg(mblk_t * mp,ssize_t len)11248329232eSGordon Ross pullupmsg(mblk_t *mp, ssize_t len)
11258329232eSGordon Ross {
11268329232eSGordon Ross mblk_t *bp, *b_cont;
11278329232eSGordon Ross dblk_t *dbp;
11288329232eSGordon Ross ssize_t n;
11298329232eSGordon Ross
11308329232eSGordon Ross ASSERT(mp->b_datap->db_ref > 0);
11318329232eSGordon Ross ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
11328329232eSGordon Ross
11338329232eSGordon Ross /*
11348329232eSGordon Ross * We won't handle Multidata message, since it contains
11358329232eSGordon Ross * metadata which this function has no knowledge of; we
11368329232eSGordon Ross * assert on DEBUG, and return failure otherwise.
11378329232eSGordon Ross */
11388329232eSGordon Ross ASSERT(mp->b_datap->db_type != M_MULTIDATA);
11398329232eSGordon Ross if (mp->b_datap->db_type == M_MULTIDATA)
11408329232eSGordon Ross return (0);
11418329232eSGordon Ross
11428329232eSGordon Ross if (len == -1) {
11438329232eSGordon Ross if (mp->b_cont == NULL && str_aligned(mp->b_rptr))
11448329232eSGordon Ross return (1);
11458329232eSGordon Ross len = xmsgsize(mp);
11468329232eSGordon Ross } else {
11478329232eSGordon Ross ssize_t first_mblk_len = mp->b_wptr - mp->b_rptr;
11488329232eSGordon Ross ASSERT(first_mblk_len >= 0);
11498329232eSGordon Ross /*
11508329232eSGordon Ross * If the length is less than that of the first mblk,
11518329232eSGordon Ross * we want to pull up the message into an aligned mblk.
11528329232eSGordon Ross * Though not part of the spec, some callers assume it.
11538329232eSGordon Ross */
11548329232eSGordon Ross if (len <= first_mblk_len) {
11558329232eSGordon Ross if (str_aligned(mp->b_rptr))
11568329232eSGordon Ross return (1);
11578329232eSGordon Ross len = first_mblk_len;
11588329232eSGordon Ross } else if (xmsgsize(mp) < len)
11598329232eSGordon Ross return (0);
11608329232eSGordon Ross }
11618329232eSGordon Ross
11628329232eSGordon Ross if ((bp = allocb_tmpl(len, mp)) == NULL)
11638329232eSGordon Ross return (0);
11648329232eSGordon Ross
11658329232eSGordon Ross dbp = bp->b_datap;
11668329232eSGordon Ross *bp = *mp; /* swap mblks so bp heads the old msg... */
11678329232eSGordon Ross mp->b_datap = dbp; /* ... and mp heads the new message */
11688329232eSGordon Ross mp->b_datap->db_mblk = mp;
11698329232eSGordon Ross bp->b_datap->db_mblk = bp;
11708329232eSGordon Ross mp->b_rptr = mp->b_wptr = dbp->db_base;
11718329232eSGordon Ross
11728329232eSGordon Ross do {
11738329232eSGordon Ross ASSERT(bp->b_datap->db_ref > 0);
11748329232eSGordon Ross ASSERT(bp->b_wptr >= bp->b_rptr);
11758329232eSGordon Ross n = MIN(bp->b_wptr - bp->b_rptr, len);
11768329232eSGordon Ross ASSERT(n >= 0); /* allow zero-length mblk_t's */
11778329232eSGordon Ross if (n > 0)
11788329232eSGordon Ross bcopy(bp->b_rptr, mp->b_wptr, (size_t)n);
11798329232eSGordon Ross mp->b_wptr += n;
11808329232eSGordon Ross bp->b_rptr += n;
11818329232eSGordon Ross len -= n;
11828329232eSGordon Ross if (bp->b_rptr != bp->b_wptr)
11838329232eSGordon Ross break;
11848329232eSGordon Ross b_cont = bp->b_cont;
11858329232eSGordon Ross freeb(bp);
11868329232eSGordon Ross bp = b_cont;
11878329232eSGordon Ross } while (len && bp);
11888329232eSGordon Ross
11898329232eSGordon Ross mp->b_cont = bp; /* tack on whatever wasn't pulled up */
11908329232eSGordon Ross
11918329232eSGordon Ross return (1);
11928329232eSGordon Ross }
11938329232eSGordon Ross
11948329232eSGordon Ross /*
11958329232eSGordon Ross * Concatenate and align at least the first len bytes of common message
11968329232eSGordon Ross * type. Len == -1 means concatenate everything. The original message is
11978329232eSGordon Ross * unaltered. Returns a pointer to a new message on success, otherwise
11988329232eSGordon Ross * returns NULL.
11998329232eSGordon Ross */
12008329232eSGordon Ross mblk_t *
msgpullup(mblk_t * mp,ssize_t len)12018329232eSGordon Ross msgpullup(mblk_t *mp, ssize_t len)
12028329232eSGordon Ross {
12038329232eSGordon Ross mblk_t *newmp;
12048329232eSGordon Ross ssize_t totlen;
12058329232eSGordon Ross ssize_t n;
12068329232eSGordon Ross
12078329232eSGordon Ross /*
12088329232eSGordon Ross * We won't handle Multidata message, since it contains
12098329232eSGordon Ross * metadata which this function has no knowledge of; we
12108329232eSGordon Ross * assert on DEBUG, and return failure otherwise.
12118329232eSGordon Ross */
12128329232eSGordon Ross ASSERT(mp->b_datap->db_type != M_MULTIDATA);
12138329232eSGordon Ross if (mp->b_datap->db_type == M_MULTIDATA)
12148329232eSGordon Ross return (NULL);
12158329232eSGordon Ross
12168329232eSGordon Ross totlen = xmsgsize(mp);
12178329232eSGordon Ross
12188329232eSGordon Ross if ((len > 0) && (len > totlen))
12198329232eSGordon Ross return (NULL);
12208329232eSGordon Ross
12218329232eSGordon Ross /*
12228329232eSGordon Ross * Copy all of the first msg type into one new mblk, then dupmsg
12238329232eSGordon Ross * and link the rest onto this.
12248329232eSGordon Ross */
12258329232eSGordon Ross
12268329232eSGordon Ross len = totlen;
12278329232eSGordon Ross
12288329232eSGordon Ross if ((newmp = allocb_tmpl(len, mp)) == NULL)
12298329232eSGordon Ross return (NULL);
12308329232eSGordon Ross
12318329232eSGordon Ross newmp->b_flag = mp->b_flag;
12328329232eSGordon Ross newmp->b_band = mp->b_band;
12338329232eSGordon Ross
12348329232eSGordon Ross while (len > 0) {
12358329232eSGordon Ross n = mp->b_wptr - mp->b_rptr;
12368329232eSGordon Ross ASSERT(n >= 0); /* allow zero-length mblk_t's */
12378329232eSGordon Ross if (n > 0)
12388329232eSGordon Ross bcopy(mp->b_rptr, newmp->b_wptr, n);
12398329232eSGordon Ross newmp->b_wptr += n;
12408329232eSGordon Ross len -= n;
12418329232eSGordon Ross mp = mp->b_cont;
12428329232eSGordon Ross }
12438329232eSGordon Ross
12448329232eSGordon Ross if (mp != NULL) {
12458329232eSGordon Ross newmp->b_cont = dupmsg(mp);
12468329232eSGordon Ross if (newmp->b_cont == NULL) {
12478329232eSGordon Ross freemsg(newmp);
12488329232eSGordon Ross return (NULL);
12498329232eSGordon Ross }
12508329232eSGordon Ross }
12518329232eSGordon Ross
12528329232eSGordon Ross return (newmp);
12538329232eSGordon Ross }
12548329232eSGordon Ross
12558329232eSGordon Ross /*
12568329232eSGordon Ross * Trim bytes from message
12578329232eSGordon Ross * len > 0, trim from head
12588329232eSGordon Ross * len < 0, trim from tail
12598329232eSGordon Ross * Returns 1 on success, 0 on failure.
12608329232eSGordon Ross */
12618329232eSGordon Ross int
adjmsg(mblk_t * mp,ssize_t len)12628329232eSGordon Ross adjmsg(mblk_t *mp, ssize_t len)
12638329232eSGordon Ross {
12648329232eSGordon Ross mblk_t *bp;
12658329232eSGordon Ross mblk_t *save_bp = NULL;
12668329232eSGordon Ross mblk_t *prev_bp;
12678329232eSGordon Ross mblk_t *bcont;
12688329232eSGordon Ross unsigned char type;
12698329232eSGordon Ross ssize_t n;
12708329232eSGordon Ross int fromhead;
12718329232eSGordon Ross int first;
12728329232eSGordon Ross
12738329232eSGordon Ross ASSERT(mp != NULL);
12748329232eSGordon Ross /*
12758329232eSGordon Ross * We won't handle Multidata message, since it contains
12768329232eSGordon Ross * metadata which this function has no knowledge of; we
12778329232eSGordon Ross * assert on DEBUG, and return failure otherwise.
12788329232eSGordon Ross */
12798329232eSGordon Ross ASSERT(mp->b_datap->db_type != M_MULTIDATA);
12808329232eSGordon Ross if (mp->b_datap->db_type == M_MULTIDATA)
12818329232eSGordon Ross return (0);
12828329232eSGordon Ross
12838329232eSGordon Ross if (len < 0) {
12848329232eSGordon Ross fromhead = 0;
12858329232eSGordon Ross len = -len;
12868329232eSGordon Ross } else {
12878329232eSGordon Ross fromhead = 1;
12888329232eSGordon Ross }
12898329232eSGordon Ross
12908329232eSGordon Ross if (xmsgsize(mp) < len)
12918329232eSGordon Ross return (0);
12928329232eSGordon Ross
12938329232eSGordon Ross if (fromhead) {
12948329232eSGordon Ross first = 1;
12958329232eSGordon Ross while (len) {
12968329232eSGordon Ross ASSERT(mp->b_wptr >= mp->b_rptr);
12978329232eSGordon Ross n = MIN(mp->b_wptr - mp->b_rptr, len);
12988329232eSGordon Ross mp->b_rptr += n;
12998329232eSGordon Ross len -= n;
13008329232eSGordon Ross
13018329232eSGordon Ross /*
13028329232eSGordon Ross * If this is not the first zero length
13038329232eSGordon Ross * message remove it
13048329232eSGordon Ross */
13058329232eSGordon Ross if (!first && (mp->b_wptr == mp->b_rptr)) {
13068329232eSGordon Ross bcont = mp->b_cont;
13078329232eSGordon Ross freeb(mp);
13088329232eSGordon Ross mp = save_bp->b_cont = bcont;
13098329232eSGordon Ross } else {
13108329232eSGordon Ross save_bp = mp;
13118329232eSGordon Ross mp = mp->b_cont;
13128329232eSGordon Ross }
13138329232eSGordon Ross first = 0;
13148329232eSGordon Ross }
13158329232eSGordon Ross } else {
13168329232eSGordon Ross type = mp->b_datap->db_type;
13178329232eSGordon Ross while (len) {
13188329232eSGordon Ross bp = mp;
13198329232eSGordon Ross save_bp = NULL;
13208329232eSGordon Ross
13218329232eSGordon Ross /*
13228329232eSGordon Ross * Find the last message of same type
13238329232eSGordon Ross */
13248329232eSGordon Ross while (bp && bp->b_datap->db_type == type) {
13258329232eSGordon Ross ASSERT(bp->b_wptr >= bp->b_rptr);
13268329232eSGordon Ross prev_bp = save_bp;
13278329232eSGordon Ross save_bp = bp;
13288329232eSGordon Ross bp = bp->b_cont;
13298329232eSGordon Ross }
13308329232eSGordon Ross if (save_bp == NULL)
13318329232eSGordon Ross break;
13328329232eSGordon Ross n = MIN(save_bp->b_wptr - save_bp->b_rptr, len);
13338329232eSGordon Ross save_bp->b_wptr -= n;
13348329232eSGordon Ross len -= n;
13358329232eSGordon Ross
13368329232eSGordon Ross /*
13378329232eSGordon Ross * If this is not the first message
13388329232eSGordon Ross * and we have taken away everything
13398329232eSGordon Ross * from this message, remove it
13408329232eSGordon Ross */
13418329232eSGordon Ross
13428329232eSGordon Ross if ((save_bp != mp) &&
13438329232eSGordon Ross (save_bp->b_wptr == save_bp->b_rptr)) {
13448329232eSGordon Ross bcont = save_bp->b_cont;
13458329232eSGordon Ross freeb(save_bp);
13468329232eSGordon Ross prev_bp->b_cont = bcont;
13478329232eSGordon Ross }
13488329232eSGordon Ross }
13498329232eSGordon Ross }
13508329232eSGordon Ross return (1);
13518329232eSGordon Ross }
13528329232eSGordon Ross
13538329232eSGordon Ross /*
13548329232eSGordon Ross * get number of data bytes in message
13558329232eSGordon Ross */
13568329232eSGordon Ross size_t
msgdsize(mblk_t * bp)13578329232eSGordon Ross msgdsize(mblk_t *bp)
13588329232eSGordon Ross {
13598329232eSGordon Ross size_t count = 0;
13608329232eSGordon Ross
13618329232eSGordon Ross for (; bp; bp = bp->b_cont)
13628329232eSGordon Ross if (bp->b_datap->db_type == M_DATA) {
13638329232eSGordon Ross ASSERT(bp->b_wptr >= bp->b_rptr);
13648329232eSGordon Ross count += bp->b_wptr - bp->b_rptr;
13658329232eSGordon Ross }
13668329232eSGordon Ross return (count);
13678329232eSGordon Ross }
13688329232eSGordon Ross
13698329232eSGordon Ross /* getq() etc to EOF removed */
1370