/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 1994-2003 Sun Microsytems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #ifdef _KERNEL #include /* for bzero */ #include #include #else /* _KERNEL */ #include /* for memset */ #endif /* _KERNEL */ #include "tnf_buf.h" #ifdef TNFWB_DEBUG #ifdef _KERNEL #error TNFWB_DEBUG #else /* _KERNEL */ #include #include #endif /* _KERNEL */ #endif /* TNFW_DEBUG */ /* * Defines */ #define TNFW_B_FW_INVALID 0xffffffff #define TNFW_B_ALLOC_LO_SELECTOR 0x1 #define TNFW_B_MAXALLOCTRY 200 #ifdef TNF_BLOCK_STATS static struct { int tnf_block_allocs; int tnf_block_tries; int tnf_max_block_tries; int tnf_tag_blocks; int tnf_generation_laps; int tnf_a_locks; int tnf_b_locks; } tnf_block_stats; #endif /* * Regular record tag pointer - CAUTION - has to be in sync with tnf_tag * macro in writer.h */ #define TNFW_B_TAG_DIFF(item, ref) \ ((TNF_REF32_MAKE_PERMANENT((tnf_ref32_t) \ ((char *)(item) - (char *)(ref)))) | TNF_REF32_T_TAG) /* * Exported interface by buffering layer to indicate where fowarding ptrs * for file header and block header are. */ static tnf_buf_header_t forwarding_ptrs = {NULL, NULL, NULL}; tnf_buf_header_t *_tnf_buf_headers_p = &forwarding_ptrs; #ifdef _KERNEL extern volatile caddr_t tnf_buf; static kmutex_t hintlock; #endif /* * (Private) Allocate a new block. Return NULL on failure. 'istag' * is true if the block is to be non-reclaimable. */ static tnf_block_header_t * tnfw_b_alloc_block(TNFW_B_WCB *wcb, enum tnf_alloc_mode istag) { tnf_block_header_t *block; uint_t hint_hi, hint_lo; uint_t new_hint_hi, new_hint_lo; uint_t generation; uint_t blocknum; uint_t prev_gen = 0; uint_t prev_block = 0; uint_t i, b; boolean_t gotit = B_FALSE; volatile tnf_buf_file_header_t *fh; #ifdef TNF_BLOCK_STATS register int tag_blocks = 0, generation_laps = 0, a_locks = 0, b_locks = 0; #endif #ifdef _TNF_VERBOSE fprintf(stderr, "tnfw_b_alloc_block: \n"); #endif if (_tnfw_b_control->tnf_state != TNFW_B_RUNNING) { #ifndef _KERNEL if (_tnfw_b_control->tnf_state == TNFW_B_NOBUFFER) if (_tnfw_b_control->tnf_init_callback() == 0) return (NULL); #endif /* _KERNEL */ if (TNFW_B_IS_STOPPED(_tnfw_b_control->tnf_state)) return (NULL); if (_tnfw_b_control->tnf_state == TNFW_B_BROKEN) return (NULL); } /* LINTED pointer cast may result in improper alignment */ fh = (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; if (!wcb->tnfw_w_initialized) { /* Get the block shift and generation shift values. */ b = 1; wcb->tnfw_w_block_shift = wcb->tnfw_w_gen_shift = 0; while (b != fh->com.block_size) { b <<= 1; ++wcb->tnfw_w_block_shift; } b = 1; while (b < fh->com.block_count) { b <<= 1; ++wcb->tnfw_w_gen_shift; } wcb->tnfw_w_pid = _tnfw_b_control->tnf_pid; wcb->tnfw_w_initialized = B_TRUE; } /* * If we need a tag block, check the reserved tag block space * first. fh->next_tag_alloc is only a hint; it is updated * without concurrency control. */ if (istag && fh->next_tag_alloc < TNFW_B_DATA_BLOCK_BEGIN) { i = fh->next_tag_alloc; do { /* LINTED pointer cast */ block = (tnf_block_header_t *) ((char *) fh + i); if (!tnfw_b_get_lock(&block->A_lock) && block->generation == 0) break; i += fh->com.block_size; } while (i < TNFW_B_DATA_BLOCK_BEGIN); if (i < TNFW_B_DATA_BLOCK_BEGIN) { if (i > fh->next_tag_alloc) fh->next_tag_alloc = i; blocknum = i >> wcb->tnfw_w_block_shift; if (blocknum > fh->com.blocks_valid) fh->com.blocks_valid = blocknum; /* LINTED pointer subtraction casted to 32 bits */ block->tag = TNFW_B_TAG_DIFF( forwarding_ptrs.fw_block_header, fh); /* LINTED constant truncated by assignment */ block->generation = TNF_TAG_GENERATION_NUM; block->bytes_valid = sizeof (tnf_block_header_t); block->next_block = NULL; tnfw_b_clear_lock(&block->A_lock); return (block); } } for (i = 0; !gotit && i != TNFW_B_MAXALLOCTRY; ++i) { hint_hi = fh->next_alloc.hi; hint_lo = (hint_hi & TNFW_B_ALLOC_LO_SELECTOR) ? fh->next_alloc.lo[1] : fh->next_alloc.lo[0]; generation = (hint_hi << (32 - wcb->tnfw_w_gen_shift)) | (hint_lo >> wcb->tnfw_w_gen_shift); blocknum = hint_lo & ((1 << wcb->tnfw_w_gen_shift) - 1); #ifdef TNFWB_DEBUG fprintf(stderr, "alloc_block (%d): read hint (%d, %d)\n", thr_self(), generation, blocknum); #endif if ((prev_gen == generation && prev_block > blocknum) || prev_gen > generation) { generation = prev_gen; blocknum = prev_block; } #ifdef TNFWB_DEBUG fprintf(stderr, "alloc_block (%d): trying blocknum = %d, gen %d\n", thr_self(), blocknum, generation); #endif block = (tnf_block_header_t *) /* LINTED pointer cast may result in improper alignment */ ((char *)fh + blocknum * fh->com.block_size); #ifdef TNF_BLOCK_STATS if (block->generation == TNF_TAG_GENERATION_NUM) ++tag_blocks; else if (block->generation >= generation) ++generation_laps; else if (tnfw_b_get_lock(&block->A_lock)) ++a_locks; else if (block->generation == TNF_TAG_GENERATION_NUM) ++tag_blocks; else if (block->generation >= generation) ++generation_laps; else if (tnfw_b_get_lock(&block->B_lock)) { tnfw_b_clear_lock(&block->A_lock); ++b_locks; } else gotit = B_TRUE; #else if (block->generation < generation && !tnfw_b_get_lock(&block->A_lock)) { if (block->generation < generation && !tnfw_b_get_lock(&block->B_lock)) { gotit = B_TRUE; } else { tnfw_b_clear_lock(&block->A_lock); } } #endif prev_block = blocknum + 1; prev_gen = generation; if (prev_block == fh->com.block_count) { prev_block = TNFW_B_DATA_BLOCK_BEGIN >> wcb->tnfw_w_block_shift; ++prev_gen; } if (blocknum > fh->com.blocks_valid) { fh->com.blocks_valid = blocknum; } } if (i == TNFW_B_MAXALLOCTRY) { _tnfw_b_control->tnf_state = TNFW_B_BROKEN; return (NULL); } #ifdef TNFWB_DEBUG fprintf(stderr, "alloc_block (%d): got blocknum = %d, gen %d, block at 0x%x\n", thr_self(), blocknum, generation, block); #endif /* LINTED pointer subtraction casted to 32 bits */ block->tag = TNFW_B_TAG_DIFF(forwarding_ptrs.fw_block_header, fh); block->generation = (istag) ? TNF_TAG_GENERATION_NUM : generation; block->bytes_valid = sizeof (tnf_block_header_t); block->next_block = NULL; if (istag) { tnfw_b_clear_lock(&block->A_lock); } tnfw_b_clear_lock(&block->B_lock); /* * Read the hint one more time, only update it if we'll be increasing * it */ new_hint_hi = prev_gen >> (32 - wcb->tnfw_w_gen_shift); new_hint_lo = prev_block | (prev_gen << wcb->tnfw_w_gen_shift); #ifdef _KERNEL mutex_enter(&hintlock); #endif hint_hi = fh->next_alloc.hi; hint_lo = (hint_hi & TNFW_B_ALLOC_LO_SELECTOR) ? fh->next_alloc.lo[1] : fh->next_alloc.lo[0]; if ((new_hint_hi == hint_hi && new_hint_lo > hint_lo) || new_hint_hi > hint_hi) { /* * Order is important here! It is the write to next_alloc.hi * that atomically records the new value. */ if (new_hint_hi & TNFW_B_ALLOC_LO_SELECTOR) fh->next_alloc.lo[1] = new_hint_lo; else fh->next_alloc.lo[0] = new_hint_lo; fh->next_alloc.hi = new_hint_hi; #ifdef TNFWB_DEBUG fprintf(stderr, "alloc_block (%d): wrote hint (%d, %d)\n", thr_self(), prev_gen, prev_block); #endif } #ifdef _KERNEL mutex_exit(&hintlock); #endif #ifdef TNF_BLOCK_STATS ++tnf_block_stats.tnf_block_allocs; tnf_block_stats.tnf_block_tries += i; if (i > tnf_block_stats.tnf_max_block_tries) { tnf_block_stats.tnf_max_block_tries = i; tnf_block_stats.tnf_tag_blocks = tag_blocks; tnf_block_stats.tnf_generation_laps = generation_laps; tnf_block_stats.tnf_a_locks = a_locks; tnf_block_stats.tnf_b_locks = b_locks; } #endif return (block); } static void release_block_from_pos(TNFW_B_POS * pos) { if (pos->tnfw_w_block == NULL) return; if (pos->tnfw_w_uncommitted != NULL) return; tnfw_b_clear_lock(&pos->tnfw_w_block->A_lock); pos->tnfw_w_block = NULL; } void tnfw_b_release_block(TNFW_B_WCB * wcb) { if (wcb == NULL) return; release_block_from_pos(&wcb->tnfw_w_tag_pos); release_block_from_pos(&wcb->tnfw_w_pos); } /* * Initialize a buffer. NOT RE-ENTRANT! Block sizes other than 512 * are currently rejected. The code "ought to work" with any block * size that is an integral power of 2. 'zfod' states whether we * can assume that the buffer is zero-filled (or paged-in zero-fill-on-demand). */ TNFW_B_STATUS tnfw_b_init_buffer(char *buf, int blocks, int block_size, boolean_t zfod) { int block_shift, gen_shift; int i; int file_size; unsigned b; tnf_block_header_t *block; /* LINTED pointer cast may result in improper alignment */ tnf_buf_file_header_t *fh = (tnf_buf_file_header_t *)buf; #ifdef _TNF_VERBOSE fprintf(stderr, "tnfw_b_init_buffer: \n"); #endif /* Check for 512 could go away. */ if (block_size != 512 || block_size < sizeof (tnf_buf_file_header_t)) return (TNFW_B_BAD_BLOCK_SIZE); /* * Check to see if block size is a power of 2, and get * log2(block size). */ for (b = (unsigned)block_size, block_shift = 0; (b & 1) == 0; b >>= 1) ++block_shift; if (b != 1) return (TNFW_B_BAD_BLOCK_SIZE); gen_shift = 0; while (b < blocks) { b <<= 1; ++gen_shift; } /* reserve first two words for file header tag and block header tag */ forwarding_ptrs.fw_file_header = (char *)fh + block_size; forwarding_ptrs.fw_block_header = (char *)fh + block_size + sizeof (tnf_ref32_t); forwarding_ptrs.fw_root = (char *)fh + block_size + (2 * sizeof (tnf_ref32_t)); /* LINTED size of tnf_ref_32_t known to be 32 */ fh->next_fw_alloc = block_size + (3 * sizeof (tnf_ref32_t)); /* fill in rest of file header */ fh->magic = TNF_MAGIC; /* Self relative pointer to tag */ /* LINTED pointer subtraction casted to 32 bits */ fh->com.tag = TNFW_B_TAG_DIFF(forwarding_ptrs.fw_file_header, fh); fh->com.file_version = TNF_FILE_VERSION; fh->com.file_header_size = sizeof (tnf_file_header_t); /* fill in fh->com.file_log_size */ b = 1; file_size = blocks * block_size; fh->com.file_log_size = 0; while (b < file_size) { b <<= 1; ++fh->com.file_log_size; } fh->com.block_header_size = sizeof (tnf_block_header_t); fh->com.block_size = block_size; fh->com.directory_size = TNFW_B_FW_ZONE; fh->com.block_count = blocks; fh->com.blocks_valid = TNFW_B_FW_ZONE >> block_shift; if (fh->com.blocks_valid == 0) fh->com.blocks_valid = 1; fh->next_tag_alloc = TNFW_B_FW_ZONE; fh->next_alloc.hi = 0; fh->next_alloc.lo[0] = (1 << gen_shift) | (TNFW_B_DATA_BLOCK_BEGIN >> block_shift); #ifdef TNFWB_DEBUG fprintf(stderr, "gen_shift = %d, blocks_valid = %d\n", gen_shift, fh->com.blocks_valid); fprintf(stderr, "alloc hint initialized to (%d, %d, %d)\n", fh->next_alloc.hi, fh->next_alloc.lo[0], fh->next_alloc.lo[1]); #endif if (!zfod) { for (i = 1; i < (TNFW_B_FW_ZONE >> block_shift); ++i) { #ifdef _KERNEL bzero(buf + (i << block_shift), block_size); #else (void) memset(buf + (i << block_shift), 0, block_size); #endif } for (; i != blocks; ++i) { block = (tnf_block_header_t *) /* LINTED pointer cast */ (buf + (i << block_shift)); block->tag = 0; block->generation = 0; tnfw_b_clear_lock(&block->A_lock); tnfw_b_clear_lock(&block->B_lock); } } #ifdef _KERNEL mutex_init(&hintlock, "tnf buffer hint lock", MUTEX_SPIN_DEFAULT, (void *) ipltospl(LOCK_LEVEL)); #endif return (TNFW_B_OK); } /* * */ void * tnfw_b_alloc(TNFW_B_WCB *wcb, size_t size, enum tnf_alloc_mode istag) { TNFW_B_POS *pos; int offset; void *destp; volatile tnf_buf_file_header_t *fh; tnf_block_header_t *block, *new_block; #ifdef _TNF_VERBOSE fprintf(stderr, "tnfw_b_alloc: \n"); #endif if (_tnfw_b_control->tnf_state != TNFW_B_RUNNING) { if (TNFW_B_IS_STOPPED(_tnfw_b_control->tnf_state)) return (NULL); if (_tnfw_b_control->tnf_state == TNFW_B_FORKED && _tnfw_b_control->tnf_pid != wcb->tnfw_w_pid) { wcb->tnfw_w_pos.tnfw_w_block = wcb->tnfw_w_pos.tnfw_w_uncommitted = wcb->tnfw_w_tag_pos.tnfw_w_block = wcb->tnfw_w_tag_pos.tnfw_w_uncommitted = NULL; wcb->tnfw_w_pid = _tnfw_b_control->tnf_pid; _tnfw_b_control->tnf_fork_callback(); } } /* Round size up to a multiple of 8. */ size = (size + 7) & ~7; /* LINTED pointer cast may result in improper alignment */ fh = (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; pos = (istag) ? &wcb->tnfw_w_tag_pos : &wcb->tnfw_w_pos; block = pos->tnfw_w_block; /* Check size within range. */ #ifdef TNFWB_SAFER if (size > fh->com.block_size - sizeof (tnf_block_header_t)) /* TNFW_B_RECORD_TOO_BIG */ return (NULL); #endif offset = pos->tnfw_w_write_off; #ifdef TNFWB_MAY_RELEASE_A_LOCK if (block != NULL && wcb->tnfw_w_a_lock_released) { /* re-acquire the A-lock for the current block */ if (!tnfw_b_get_lock(&block->A_lock)) { wcb->tnfw_w_a_lock_released = B_FALSE; if (wcb->tnfw_w_generation != block->generation) { tnfw_b_clear_lock(&block->A_lock); wcb->tnfw_w_pos.tnfw_w_block = NULL; } } else { wcb->tnfw_w_pos.tnfw_w_block = NULL; } } #endif if (block == NULL || offset + size > fh->com.block_size) { new_block = tnfw_b_alloc_block(wcb, istag); if (new_block == NULL) { /* TNFW_B_ACKPHT */ return (NULL); } #ifdef TNFWB_DEBUG fprintf(stderr, "wcb 0x%x: new block at 0x%x, old block is 0x%x, " "uncommitted is 0x%x\n", wcb, new_block, block, pos->tnfw_w_uncommitted); #endif if (block != NULL) { /* XXXX is this what we want for padding? */ #ifdef _KERNEL (void) bzero((char *)block + offset, fh->com.block_size - offset); #else (void) memset((char *)block + offset, 0, fh->com.block_size - offset); #endif if (pos->tnfw_w_uncommitted == NULL) { #ifdef TNFWB_MAY_RELEASE_A_LOCK /* Could still be holding the A-lock on block */ if (!wcb->tnfw_w_a_lock_released) tnfw_b_clear_lock(&block->A_lock); #else /* Definitely still holding the A-lock */ tnfw_b_clear_lock(&block->A_lock); #endif /* TNFWB_MAY_RELEASE_A_LOCK */ } } /* Add new_block to the list of uncommitted blocks. */ if (pos->tnfw_w_uncommitted == NULL) { pos->tnfw_w_uncommitted = new_block; } else { /* Assert(block != NULL); */ block->next_block = new_block; } pos->tnfw_w_block = new_block; pos->tnfw_w_write_off = new_block->bytes_valid; } else if (pos->tnfw_w_uncommitted == NULL) { pos->tnfw_w_uncommitted = block; } destp = (char *)pos->tnfw_w_block + pos->tnfw_w_write_off; pos->tnfw_w_write_off += size; /* * Unconditionally write a 0 into the last word allocated, * in case we left an alignment gap. (Assume that doing an * unconditional write is cheaper than testing and branching * around the write half the time.) */ /* LINTED pointer cast may result in improper alignment */ *((int *)((char *) destp + size - sizeof (int))) = 0; #ifdef _TNF_VERBOSE fprintf(stderr, "tnfw_b_alloc returning %p\n", destp); #endif return (destp); } /* * */ TNFW_B_STATUS tnfw_b_xcommit(TNFW_B_WCB *wcb) { TNFW_B_POS *pos; tnf_block_header_t *block; volatile tnf_buf_file_header_t *fh = /* LINTED pointer cast may result in improper alignment */ (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; #ifdef TNFWB_DEBUG fprintf(stderr, "tnfw_b_xcommit \n"); #endif /* * cope with the normal record block(s) first */ pos = &wcb->tnfw_w_pos; block = pos->tnfw_w_uncommitted; while (block && (block != pos->tnfw_w_block)) { #ifdef TNFWB_DEBUG fprintf(stderr, "commit %d: block = 0x%x, last = 0x%x\n", block->generation, block, pos->tnfw_w_block); #endif block->bytes_valid = fh->com.block_size; pos->tnfw_w_uncommitted = block->next_block; tnfw_b_clear_lock(&block->A_lock); block = pos->tnfw_w_uncommitted; } if (block != NULL) { #ifdef TNFWB_DEBUG fprintf(stderr, "commit last %d: block = 0x%x, offset = 0x%x\n", block->generation, block, pos->tnfw_w_write_off); #endif block->bytes_valid = pos->tnfw_w_write_off; } pos->tnfw_w_uncommitted = NULL; #ifdef TNFWB_MAY_RELEASE_A_LOCK if (0) { /* XXXX Do we or don't we clear this lock? */ wcb->tnfw_w_generation = block->generation; tnfw_b_clear_lock(&block->A_lock); wcb->tnfw_w_a_lock_released = B_TRUE; } #endif /* * cope with the tag block(s) */ pos = &wcb->tnfw_w_tag_pos; block = pos->tnfw_w_uncommitted; while (block && (block != pos->tnfw_w_block)) { #ifdef TNFWB_DEBUG fprintf(stderr, "commit %d: block = 0x%x, last = 0x%x\n", thr_self(), block, pos->tnfw_w_block); #endif block->bytes_valid = fh->com.block_size; pos->tnfw_w_uncommitted = block->next_block; block = pos->tnfw_w_uncommitted; } if (block != NULL) block->bytes_valid = pos->tnfw_w_write_off; pos->tnfw_w_uncommitted = NULL; return (TNFW_B_OK); } /* * */ TNFW_B_STATUS tnfw_b_xabort(TNFW_B_WCB *wcb) { TNFW_B_POS *pos = &wcb->tnfw_w_pos; tnf_block_header_t *block, *next; volatile tnf_buf_file_header_t *fh = /* LINTED pointer cast may result in improper alignment */ (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; block = pos->tnfw_w_block = pos->tnfw_w_uncommitted; if (block != NULL) { pos->tnfw_w_write_off = block->bytes_valid; #ifdef TNFWB_MAY_RELEASE_A_LOCK if (0) { /* XXXX */ tnfw_b_clear_lock(&block->A_lock); wcb->tnfw_w_generation = block->generation; wcb->tnfw_w_a_lock_released = B_TRUE; } #endif block = block->next_block; } while (block != NULL) { next = block->next_block; tnfw_b_clear_lock(&block->A_lock); block = next; } pos->tnfw_w_uncommitted = NULL; pos = &wcb->tnfw_w_tag_pos; block = pos->tnfw_w_uncommitted; while (block && (block != pos->tnfw_w_block)) { block->bytes_valid = fh->com.block_size; pos->tnfw_w_uncommitted = block->next_block; block = pos->tnfw_w_uncommitted; } if (block != NULL) block->bytes_valid = pos->tnfw_w_write_off; pos->tnfw_w_uncommitted = NULL; return (TNFW_B_OK); } /* * The kernel version is different because we can use a spin mutex * in the kernel, and not all SPARC systems support the SWAP instruction. */ #ifdef _KERNEL /*ARGSUSED0*/ tnf_uint32_t * tnfw_b_fw_alloc(TNFW_B_WCB *wcb) { tnf_uint32_t *ret_val; volatile tnf_buf_file_header_t *fh = /* LINTED pointer cast may result in improper alignment */ (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; tnf_uint32_t *zone_end = (tnf_uint32_t *)((char *)fh + TNFW_B_FW_ZONE); mutex_enter(&hintlock); ret_val = (tnf_uint32_t *)((char *)fh + fh->next_fw_alloc); if (ret_val != zone_end) fh->next_fw_alloc += sizeof (tnf_uint32_t); mutex_exit(&hintlock); return ((ret_val != zone_end) ? ret_val : NULL); } #else /*ARGSUSED0*/ tnf_uint32_t * tnfw_b_fw_alloc(TNFW_B_WCB *wcb) { volatile tnf_buf_file_header_t *fh = /* LINTED pointer cast may result in improper alignment */ (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; /* LINTED pointer cast may result in improper alignment */ uint_t *hint = (uint_t *)((uintptr_t)fh + fh->next_fw_alloc); /* LINTED pointer cast may result in improper alignment */ ulong_t *zone_end = (ulong_t *)((uintptr_t)fh + TNFW_B_FW_ZONE); u_long swapin; char tmp_buf[512]; tnf_uint32_t *retval; #ifdef VERYVERBOSE sprintf(tmp_buf, "tnfw_b_vw_alloc: begin\n"); (void) write(2, tmp_buf, strlen(tmp_buf)); #endif #ifdef VERYVERBOSE sprintf(tmp_buf, "tnfw_b_vw_alloc: (1)hint=%p\n", hint); (void) write(2, tmp_buf, strlen(tmp_buf)); #endif while ((uintptr_t)hint != (uintptr_t)zone_end) { #ifdef VERYVERBOSE sprintf(tmp_buf, "tnfw_b_vw_alloc: (2)hint=%p,zone_end=%p\n", hint, zone_end); (void) write(2, tmp_buf, strlen(tmp_buf)); #endif #ifdef VERYVERBOSE sprintf(tmp_buf, "tnfw_b_fw_alloc: fh = %p, next->alloc = %d\n", fh, fh->next_fw_alloc); (void) write(2, tmp_buf, strlen(tmp_buf)); sprintf(tmp_buf, "tnfw_b_vw_alloc: about to deref hint\n"); (void) write(2, tmp_buf, strlen(tmp_buf)); sprintf(tmp_buf, "tnfw_b_vw_alloc: *hint=%ld\n", *hint); (void) write(2, tmp_buf, strlen(tmp_buf)); #endif if (*hint == 0) { swapin = tnfw_b_atomic_swap(hint, TNFW_B_FW_INVALID); if (swapin != 0) { if (swapin != (unsigned)TNFW_B_FW_INVALID) { /* restore */ *hint = swapin; } } else { break; } } ++hint; #ifdef VERYVERBOSE sprintf(tmp_buf, "tnfw_b_vw_alloc: (3)hint=%p\n", hint); (void) write(2, tmp_buf, strlen(tmp_buf)); #endif } /* LINTED pointer subtraction casted to 32 bits */ fh->next_fw_alloc = (uint_t) ((char *)hint - (char *)fh); retval = (((uintptr_t)hint != (uintptr_t)zone_end) ? (tnf_uint32_t *)hint : NULL); #ifdef VERYVERBOSE sprintf(tmp_buf, "tnfw_b_vw_alloc: returning %p", retval); (void) write(2, tmp_buf, strlen(tmp_buf)); #endif return (retval); } #endif /* _KERNEL */