1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1994-2003 Sun Microsytems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #ifdef _KERNEL 32 #include <sys/systm.h> /* for bzero */ 33 #include <sys/spl.h> 34 #include <sys/cmn_err.h> 35 #else /* _KERNEL */ 36 #include <string.h> /* for memset */ 37 #endif /* _KERNEL */ 38 39 #include "tnf_buf.h" 40 41 #ifdef TNFWB_DEBUG 42 #ifdef _KERNEL 43 #error TNFWB_DEBUG 44 #else /* _KERNEL */ 45 #include <stdio.h> 46 #include <thread.h> 47 #endif /* _KERNEL */ 48 #endif /* TNFW_DEBUG */ 49 50 /* 51 * Defines 52 */ 53 54 #define TNFW_B_FW_INVALID 0xffffffff 55 #define TNFW_B_ALLOC_LO_SELECTOR 0x1 56 #define TNFW_B_MAXALLOCTRY 200 57 58 #ifdef TNF_BLOCK_STATS 59 static struct { 60 int tnf_block_allocs; 61 int tnf_block_tries; 62 int tnf_max_block_tries; 63 int tnf_tag_blocks; 64 int tnf_generation_laps; 65 int tnf_a_locks; 66 int tnf_b_locks; 67 } tnf_block_stats; 68 #endif 69 70 /* 71 * Regular record tag pointer - CAUTION - has to be in sync with tnf_tag 72 * macro in writer.h 73 */ 74 #define TNFW_B_TAG_DIFF(item, ref) \ 75 ((TNF_REF32_MAKE_PERMANENT((tnf_ref32_t) \ 76 ((char *)(item) - (char *)(ref)))) | TNF_REF32_T_TAG) 77 78 /* 79 * Exported interface by buffering layer to indicate where fowarding ptrs 80 * for file header and block header are. 81 */ 82 static tnf_buf_header_t forwarding_ptrs = {NULL, NULL, NULL}; 83 tnf_buf_header_t *_tnf_buf_headers_p = &forwarding_ptrs; 84 85 #ifdef _KERNEL 86 extern volatile caddr_t tnf_buf; 87 88 static kmutex_t hintlock; 89 #endif 90 91 /* 92 * (Private) Allocate a new block. Return NULL on failure. 'istag' 93 * is true if the block is to be non-reclaimable. 94 */ 95 static tnf_block_header_t * 96 tnfw_b_alloc_block(TNFW_B_WCB *wcb, enum tnf_alloc_mode istag) 97 { 98 tnf_block_header_t *block; 99 uint_t hint_hi, hint_lo; 100 uint_t new_hint_hi, new_hint_lo; 101 uint_t generation; 102 uint_t blocknum; 103 uint_t prev_gen = 0; 104 uint_t prev_block = 0; 105 uint_t i, b; 106 boolean_t gotit = B_FALSE; 107 volatile tnf_buf_file_header_t *fh; 108 #ifdef TNF_BLOCK_STATS 109 register int tag_blocks = 0, generation_laps = 0, a_locks = 0, 110 b_locks = 0; 111 #endif 112 113 #ifdef _TNF_VERBOSE 114 fprintf(stderr, "tnfw_b_alloc_block: \n"); 115 #endif 116 117 if (_tnfw_b_control->tnf_state != TNFW_B_RUNNING) { 118 #ifndef _KERNEL 119 if (_tnfw_b_control->tnf_state == TNFW_B_NOBUFFER) 120 if (_tnfw_b_control->tnf_init_callback() == 0) 121 return (NULL); 122 #endif /* _KERNEL */ 123 if (TNFW_B_IS_STOPPED(_tnfw_b_control->tnf_state)) 124 return (NULL); 125 if (_tnfw_b_control->tnf_state == TNFW_B_BROKEN) 126 return (NULL); 127 } 128 129 /* LINTED pointer cast may result in improper alignment */ 130 fh = (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; 131 if (!wcb->tnfw_w_initialized) { 132 /* Get the block shift and generation shift values. */ 133 b = 1; 134 wcb->tnfw_w_block_shift = wcb->tnfw_w_gen_shift = 0; 135 while (b != fh->com.block_size) { 136 b <<= 1; 137 ++wcb->tnfw_w_block_shift; 138 } 139 b = 1; 140 while (b < fh->com.block_count) { 141 b <<= 1; 142 ++wcb->tnfw_w_gen_shift; 143 } 144 wcb->tnfw_w_pid = _tnfw_b_control->tnf_pid; 145 wcb->tnfw_w_initialized = B_TRUE; 146 } 147 148 /* 149 * If we need a tag block, check the reserved tag block space 150 * first. fh->next_tag_alloc is only a hint; it is updated 151 * without concurrency control. 152 */ 153 if (istag && fh->next_tag_alloc < TNFW_B_DATA_BLOCK_BEGIN) { 154 i = fh->next_tag_alloc; 155 do { 156 /* LINTED pointer cast */ 157 block = (tnf_block_header_t *) ((char *) fh + i); 158 if (!tnfw_b_get_lock(&block->A_lock) && 159 block->generation == 0) 160 break; 161 i += fh->com.block_size; 162 } while (i < TNFW_B_DATA_BLOCK_BEGIN); 163 if (i < TNFW_B_DATA_BLOCK_BEGIN) { 164 if (i > fh->next_tag_alloc) 165 fh->next_tag_alloc = i; 166 blocknum = i >> wcb->tnfw_w_block_shift; 167 if (blocknum > fh->com.blocks_valid) 168 fh->com.blocks_valid = blocknum; 169 /* LINTED pointer subtraction casted to 32 bits */ 170 block->tag = TNFW_B_TAG_DIFF( 171 forwarding_ptrs.fw_block_header, fh); 172 /* LINTED constant truncated by assignment */ 173 block->generation = TNF_TAG_GENERATION_NUM; 174 block->bytes_valid = sizeof (tnf_block_header_t); 175 block->next_block = NULL; 176 tnfw_b_clear_lock(&block->A_lock); 177 return (block); 178 } 179 } 180 181 for (i = 0; !gotit && i != TNFW_B_MAXALLOCTRY; ++i) { 182 hint_hi = fh->next_alloc.hi; 183 hint_lo = (hint_hi & TNFW_B_ALLOC_LO_SELECTOR) 184 ? fh->next_alloc.lo[1] : fh->next_alloc.lo[0]; 185 generation = (hint_hi << (32 - wcb->tnfw_w_gen_shift)) | 186 (hint_lo >> wcb->tnfw_w_gen_shift); 187 blocknum = hint_lo & ((1 << wcb->tnfw_w_gen_shift) - 1); 188 #ifdef TNFWB_DEBUG 189 fprintf(stderr, "alloc_block (%d): read hint (%d, %d)\n", 190 thr_self(), generation, blocknum); 191 #endif 192 if ((prev_gen == generation && prev_block > blocknum) || 193 prev_gen > generation) { 194 generation = prev_gen; 195 blocknum = prev_block; 196 } 197 #ifdef TNFWB_DEBUG 198 fprintf(stderr, 199 "alloc_block (%d): trying blocknum = %d, gen %d\n", 200 thr_self(), blocknum, generation); 201 #endif 202 block = (tnf_block_header_t *) 203 /* LINTED pointer cast may result in improper alignment */ 204 ((char *)fh + blocknum * fh->com.block_size); 205 #ifdef TNF_BLOCK_STATS 206 if (block->generation == TNF_TAG_GENERATION_NUM) 207 ++tag_blocks; 208 else if (block->generation >= generation) 209 ++generation_laps; 210 else if (tnfw_b_get_lock(&block->A_lock)) 211 ++a_locks; 212 else if (block->generation == TNF_TAG_GENERATION_NUM) 213 ++tag_blocks; 214 else if (block->generation >= generation) 215 ++generation_laps; 216 else if (tnfw_b_get_lock(&block->B_lock)) { 217 tnfw_b_clear_lock(&block->A_lock); 218 ++b_locks; 219 } else 220 gotit = B_TRUE; 221 222 #else 223 if (block->generation < generation && 224 !tnfw_b_get_lock(&block->A_lock)) { 225 if (block->generation < generation && 226 !tnfw_b_get_lock(&block->B_lock)) { 227 gotit = B_TRUE; 228 } else { 229 tnfw_b_clear_lock(&block->A_lock); 230 } 231 } 232 #endif 233 prev_block = blocknum + 1; 234 prev_gen = generation; 235 if (prev_block == fh->com.block_count) { 236 prev_block = 237 TNFW_B_DATA_BLOCK_BEGIN >> wcb->tnfw_w_block_shift; 238 ++prev_gen; 239 } 240 if (blocknum > fh->com.blocks_valid) { 241 fh->com.blocks_valid = blocknum; 242 } 243 } 244 245 if (i == TNFW_B_MAXALLOCTRY) { 246 _tnfw_b_control->tnf_state = TNFW_B_BROKEN; 247 return (NULL); 248 } 249 #ifdef TNFWB_DEBUG 250 fprintf(stderr, 251 "alloc_block (%d): got blocknum = %d, gen %d, block at 0x%x\n", 252 thr_self(), blocknum, generation, block); 253 #endif 254 /* LINTED pointer subtraction casted to 32 bits */ 255 block->tag = TNFW_B_TAG_DIFF(forwarding_ptrs.fw_block_header, fh); 256 block->generation = (istag) ? TNF_TAG_GENERATION_NUM : generation; 257 block->bytes_valid = sizeof (tnf_block_header_t); 258 block->next_block = NULL; 259 if (istag) { 260 tnfw_b_clear_lock(&block->A_lock); 261 } 262 tnfw_b_clear_lock(&block->B_lock); 263 264 /* 265 * Read the hint one more time, only update it if we'll be increasing 266 * it 267 */ 268 new_hint_hi = prev_gen >> (32 - wcb->tnfw_w_gen_shift); 269 new_hint_lo = prev_block | (prev_gen << wcb->tnfw_w_gen_shift); 270 #ifdef _KERNEL 271 mutex_enter(&hintlock); 272 #endif 273 hint_hi = fh->next_alloc.hi; 274 hint_lo = (hint_hi & TNFW_B_ALLOC_LO_SELECTOR) ? 275 fh->next_alloc.lo[1] : fh->next_alloc.lo[0]; 276 277 if ((new_hint_hi == hint_hi && new_hint_lo > hint_lo) || 278 new_hint_hi > hint_hi) { 279 /* 280 * Order is important here! It is the write to next_alloc.hi 281 * that atomically records the new value. 282 */ 283 if (new_hint_hi & TNFW_B_ALLOC_LO_SELECTOR) 284 fh->next_alloc.lo[1] = new_hint_lo; 285 else 286 fh->next_alloc.lo[0] = new_hint_lo; 287 fh->next_alloc.hi = new_hint_hi; 288 #ifdef TNFWB_DEBUG 289 fprintf(stderr, "alloc_block (%d): wrote hint (%d, %d)\n", 290 thr_self(), prev_gen, prev_block); 291 #endif 292 } 293 #ifdef _KERNEL 294 mutex_exit(&hintlock); 295 #endif 296 #ifdef TNF_BLOCK_STATS 297 ++tnf_block_stats.tnf_block_allocs; 298 tnf_block_stats.tnf_block_tries += i; 299 if (i > tnf_block_stats.tnf_max_block_tries) { 300 tnf_block_stats.tnf_max_block_tries = i; 301 tnf_block_stats.tnf_tag_blocks = tag_blocks; 302 tnf_block_stats.tnf_generation_laps = generation_laps; 303 tnf_block_stats.tnf_a_locks = a_locks; 304 tnf_block_stats.tnf_b_locks = b_locks; 305 } 306 #endif 307 return (block); 308 } 309 310 static void release_block_from_pos(TNFW_B_POS * pos) 311 { 312 if (pos->tnfw_w_block == NULL) 313 return; 314 if (pos->tnfw_w_uncommitted != NULL) 315 return; 316 tnfw_b_clear_lock(&pos->tnfw_w_block->A_lock); 317 pos->tnfw_w_block = NULL; 318 } 319 320 void 321 tnfw_b_release_block(TNFW_B_WCB * wcb) 322 { 323 if (wcb == NULL) 324 return; 325 release_block_from_pos(&wcb->tnfw_w_tag_pos); 326 release_block_from_pos(&wcb->tnfw_w_pos); 327 } 328 329 /* 330 * Initialize a buffer. NOT RE-ENTRANT! Block sizes other than 512 331 * are currently rejected. The code "ought to work" with any block 332 * size that is an integral power of 2. 'zfod' states whether we 333 * can assume that the buffer is zero-filled (or paged-in zero-fill-on-demand). 334 */ 335 TNFW_B_STATUS 336 tnfw_b_init_buffer(char *buf, int blocks, int block_size, boolean_t zfod) 337 338 { 339 int block_shift, gen_shift; 340 int i; 341 int file_size; 342 unsigned b; 343 tnf_block_header_t *block; 344 /* LINTED pointer cast may result in improper alignment */ 345 tnf_buf_file_header_t *fh = (tnf_buf_file_header_t *)buf; 346 347 #ifdef _TNF_VERBOSE 348 fprintf(stderr, "tnfw_b_init_buffer: \n"); 349 #endif 350 351 /* Check for 512 could go away. */ 352 if (block_size != 512 || block_size < sizeof (tnf_buf_file_header_t)) 353 return (TNFW_B_BAD_BLOCK_SIZE); 354 /* 355 * Check to see if block size is a power of 2, and get 356 * log2(block size). 357 */ 358 for (b = (unsigned)block_size, block_shift = 0; (b & 1) == 0; b >>= 1) 359 ++block_shift; 360 if (b != 1) 361 return (TNFW_B_BAD_BLOCK_SIZE); 362 gen_shift = 0; 363 while (b < blocks) { 364 b <<= 1; 365 ++gen_shift; 366 } 367 /* reserve first two words for file header tag and block header tag */ 368 forwarding_ptrs.fw_file_header = (char *)fh + block_size; 369 forwarding_ptrs.fw_block_header = (char *)fh + block_size + 370 sizeof (tnf_ref32_t); 371 forwarding_ptrs.fw_root = (char *)fh + block_size + 372 (2 * sizeof (tnf_ref32_t)); 373 /* LINTED size of tnf_ref_32_t known to be 32 */ 374 fh->next_fw_alloc = block_size + (3 * sizeof (tnf_ref32_t)); 375 /* fill in rest of file header */ 376 fh->magic = TNF_MAGIC; 377 /* Self relative pointer to tag */ 378 /* LINTED pointer subtraction casted to 32 bits */ 379 fh->com.tag = TNFW_B_TAG_DIFF(forwarding_ptrs.fw_file_header, fh); 380 fh->com.file_version = TNF_FILE_VERSION; 381 fh->com.file_header_size = sizeof (tnf_file_header_t); 382 /* fill in fh->com.file_log_size */ 383 b = 1; 384 file_size = blocks * block_size; 385 fh->com.file_log_size = 0; 386 while (b < file_size) { 387 b <<= 1; 388 ++fh->com.file_log_size; 389 } 390 391 fh->com.block_header_size = sizeof (tnf_block_header_t); 392 fh->com.block_size = block_size; 393 fh->com.directory_size = TNFW_B_FW_ZONE; 394 fh->com.block_count = blocks; 395 fh->com.blocks_valid = TNFW_B_FW_ZONE >> block_shift; 396 if (fh->com.blocks_valid == 0) 397 fh->com.blocks_valid = 1; 398 fh->next_tag_alloc = TNFW_B_FW_ZONE; 399 fh->next_alloc.hi = 0; 400 fh->next_alloc.lo[0] = 401 (1 << gen_shift) | (TNFW_B_DATA_BLOCK_BEGIN >> block_shift); 402 #ifdef TNFWB_DEBUG 403 fprintf(stderr, "gen_shift = %d, blocks_valid = %d\n", 404 gen_shift, fh->com.blocks_valid); 405 fprintf(stderr, "alloc hint initialized to (%d, %d, %d)\n", 406 fh->next_alloc.hi, fh->next_alloc.lo[0], fh->next_alloc.lo[1]); 407 #endif 408 if (!zfod) { 409 for (i = 1; i < (TNFW_B_FW_ZONE >> block_shift); ++i) { 410 #ifdef _KERNEL 411 bzero(buf + (i << block_shift), block_size); 412 #else 413 (void) memset(buf + (i << block_shift), 0, block_size); 414 #endif 415 } 416 for (; i != blocks; ++i) { 417 block = (tnf_block_header_t *) 418 /* LINTED pointer cast */ 419 (buf + (i << block_shift)); 420 block->tag = 0; 421 block->generation = 0; 422 tnfw_b_clear_lock(&block->A_lock); 423 tnfw_b_clear_lock(&block->B_lock); 424 } 425 } 426 #ifdef _KERNEL 427 mutex_init(&hintlock, "tnf buffer hint lock", MUTEX_SPIN_DEFAULT, 428 (void *) ipltospl(LOCK_LEVEL)); 429 #endif 430 return (TNFW_B_OK); 431 } 432 433 /* 434 * 435 */ 436 void * 437 tnfw_b_alloc(TNFW_B_WCB *wcb, size_t size, enum tnf_alloc_mode istag) 438 { 439 TNFW_B_POS *pos; 440 int offset; 441 void *destp; 442 volatile tnf_buf_file_header_t *fh; 443 tnf_block_header_t *block, *new_block; 444 445 #ifdef _TNF_VERBOSE 446 fprintf(stderr, "tnfw_b_alloc: \n"); 447 #endif 448 449 if (_tnfw_b_control->tnf_state != TNFW_B_RUNNING) { 450 if (TNFW_B_IS_STOPPED(_tnfw_b_control->tnf_state)) 451 return (NULL); 452 if (_tnfw_b_control->tnf_state == TNFW_B_FORKED && 453 _tnfw_b_control->tnf_pid != wcb->tnfw_w_pid) { 454 wcb->tnfw_w_pos.tnfw_w_block = 455 wcb->tnfw_w_pos.tnfw_w_uncommitted = 456 wcb->tnfw_w_tag_pos.tnfw_w_block = 457 wcb->tnfw_w_tag_pos.tnfw_w_uncommitted = NULL; 458 wcb->tnfw_w_pid = _tnfw_b_control->tnf_pid; 459 _tnfw_b_control->tnf_fork_callback(); 460 } 461 } 462 463 /* Round size up to a multiple of 8. */ 464 size = (size + 7) & ~7; 465 466 /* LINTED pointer cast may result in improper alignment */ 467 fh = (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; 468 pos = (istag) ? &wcb->tnfw_w_tag_pos : &wcb->tnfw_w_pos; 469 block = pos->tnfw_w_block; 470 /* Check size within range. */ 471 #ifdef TNFWB_SAFER 472 if (size > fh->com.block_size - sizeof (tnf_block_header_t)) 473 /* TNFW_B_RECORD_TOO_BIG */ 474 return (NULL); 475 #endif 476 offset = pos->tnfw_w_write_off; 477 #ifdef TNFWB_MAY_RELEASE_A_LOCK 478 if (block != NULL && wcb->tnfw_w_a_lock_released) { 479 /* re-acquire the A-lock for the current block */ 480 if (!tnfw_b_get_lock(&block->A_lock)) { 481 wcb->tnfw_w_a_lock_released = B_FALSE; 482 if (wcb->tnfw_w_generation != block->generation) { 483 tnfw_b_clear_lock(&block->A_lock); 484 wcb->tnfw_w_pos.tnfw_w_block = NULL; 485 } 486 } else { 487 wcb->tnfw_w_pos.tnfw_w_block = NULL; 488 } 489 } 490 #endif 491 if (block == NULL || offset + size > fh->com.block_size) { 492 new_block = tnfw_b_alloc_block(wcb, istag); 493 if (new_block == NULL) { 494 /* TNFW_B_ACKPHT */ 495 return (NULL); 496 } 497 #ifdef TNFWB_DEBUG 498 fprintf(stderr, 499 "wcb 0x%x: new block at 0x%x, old block is 0x%x, " 500 "uncommitted is 0x%x\n", 501 wcb, new_block, block, pos->tnfw_w_uncommitted); 502 #endif 503 if (block != NULL) { 504 /* XXXX is this what we want for padding? */ 505 #ifdef _KERNEL 506 (void) bzero((char *)block + offset, 507 fh->com.block_size - offset); 508 #else 509 (void) memset((char *)block + offset, 0, 510 fh->com.block_size - offset); 511 #endif 512 if (pos->tnfw_w_uncommitted == NULL) { 513 #ifdef TNFWB_MAY_RELEASE_A_LOCK 514 /* Could still be holding the A-lock on block */ 515 if (!wcb->tnfw_w_a_lock_released) 516 tnfw_b_clear_lock(&block->A_lock); 517 #else 518 /* Definitely still holding the A-lock */ 519 tnfw_b_clear_lock(&block->A_lock); 520 #endif /* TNFWB_MAY_RELEASE_A_LOCK */ 521 } 522 } 523 /* Add new_block to the list of uncommitted blocks. */ 524 if (pos->tnfw_w_uncommitted == NULL) { 525 pos->tnfw_w_uncommitted = new_block; 526 } else { 527 /* Assert(block != NULL); */ 528 block->next_block = new_block; 529 } 530 pos->tnfw_w_block = new_block; 531 pos->tnfw_w_write_off = new_block->bytes_valid; 532 } else if (pos->tnfw_w_uncommitted == NULL) { 533 pos->tnfw_w_uncommitted = block; 534 } 535 destp = (char *)pos->tnfw_w_block + pos->tnfw_w_write_off; 536 pos->tnfw_w_write_off += size; 537 /* 538 * Unconditionally write a 0 into the last word allocated, 539 * in case we left an alignment gap. (Assume that doing an 540 * unconditional write is cheaper than testing and branching 541 * around the write half the time.) 542 */ 543 /* LINTED pointer cast may result in improper alignment */ 544 *((int *)((char *) destp + size - sizeof (int))) = 0; 545 546 #ifdef _TNF_VERBOSE 547 fprintf(stderr, "tnfw_b_alloc returning %p\n", destp); 548 #endif 549 return (destp); 550 } 551 552 /* 553 * 554 */ 555 TNFW_B_STATUS 556 tnfw_b_xcommit(TNFW_B_WCB *wcb) 557 { 558 TNFW_B_POS *pos; 559 tnf_block_header_t *block; 560 volatile tnf_buf_file_header_t *fh = 561 /* LINTED pointer cast may result in improper alignment */ 562 (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; 563 564 #ifdef TNFWB_DEBUG 565 fprintf(stderr, "tnfw_b_xcommit \n"); 566 #endif 567 568 /* 569 * cope with the normal record block(s) first 570 */ 571 572 pos = &wcb->tnfw_w_pos; 573 block = pos->tnfw_w_uncommitted; 574 while (block && (block != pos->tnfw_w_block)) { 575 #ifdef TNFWB_DEBUG 576 fprintf(stderr, "commit %d: block = 0x%x, last = 0x%x\n", 577 block->generation, block, pos->tnfw_w_block); 578 #endif 579 block->bytes_valid = fh->com.block_size; 580 pos->tnfw_w_uncommitted = block->next_block; 581 tnfw_b_clear_lock(&block->A_lock); 582 block = pos->tnfw_w_uncommitted; 583 } 584 if (block != NULL) { 585 #ifdef TNFWB_DEBUG 586 fprintf(stderr, "commit last %d: block = 0x%x, offset = 0x%x\n", 587 block->generation, block, pos->tnfw_w_write_off); 588 #endif 589 block->bytes_valid = pos->tnfw_w_write_off; 590 } 591 pos->tnfw_w_uncommitted = NULL; 592 #ifdef TNFWB_MAY_RELEASE_A_LOCK 593 if (0) { /* XXXX Do we or don't we clear this lock? */ 594 wcb->tnfw_w_generation = block->generation; 595 tnfw_b_clear_lock(&block->A_lock); 596 wcb->tnfw_w_a_lock_released = B_TRUE; 597 } 598 #endif 599 600 /* 601 * cope with the tag block(s) 602 */ 603 604 pos = &wcb->tnfw_w_tag_pos; 605 block = pos->tnfw_w_uncommitted; 606 while (block && (block != pos->tnfw_w_block)) { 607 #ifdef TNFWB_DEBUG 608 fprintf(stderr, "commit %d: block = 0x%x, last = 0x%x\n", 609 thr_self(), block, pos->tnfw_w_block); 610 #endif 611 block->bytes_valid = fh->com.block_size; 612 pos->tnfw_w_uncommitted = block->next_block; 613 block = pos->tnfw_w_uncommitted; 614 } 615 if (block != NULL) 616 block->bytes_valid = pos->tnfw_w_write_off; 617 pos->tnfw_w_uncommitted = NULL; 618 return (TNFW_B_OK); 619 } 620 621 /* 622 * 623 */ 624 TNFW_B_STATUS 625 tnfw_b_xabort(TNFW_B_WCB *wcb) 626 { 627 TNFW_B_POS *pos = &wcb->tnfw_w_pos; 628 tnf_block_header_t *block, *next; 629 volatile tnf_buf_file_header_t *fh = 630 /* LINTED pointer cast may result in improper alignment */ 631 (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; 632 633 block = pos->tnfw_w_block = pos->tnfw_w_uncommitted; 634 if (block != NULL) { 635 pos->tnfw_w_write_off = block->bytes_valid; 636 #ifdef TNFWB_MAY_RELEASE_A_LOCK 637 if (0) { /* XXXX */ 638 tnfw_b_clear_lock(&block->A_lock); 639 wcb->tnfw_w_generation = block->generation; 640 wcb->tnfw_w_a_lock_released = B_TRUE; 641 } 642 #endif 643 block = block->next_block; 644 } 645 while (block != NULL) { 646 next = block->next_block; 647 tnfw_b_clear_lock(&block->A_lock); 648 block = next; 649 } 650 pos->tnfw_w_uncommitted = NULL; 651 pos = &wcb->tnfw_w_tag_pos; 652 block = pos->tnfw_w_uncommitted; 653 while (block && (block != pos->tnfw_w_block)) { 654 block->bytes_valid = fh->com.block_size; 655 pos->tnfw_w_uncommitted = block->next_block; 656 block = pos->tnfw_w_uncommitted; 657 } 658 if (block != NULL) 659 block->bytes_valid = pos->tnfw_w_write_off; 660 pos->tnfw_w_uncommitted = NULL; 661 return (TNFW_B_OK); 662 } 663 664 /* 665 * The kernel version is different because we can use a spin mutex 666 * in the kernel, and not all SPARC systems support the SWAP instruction. 667 */ 668 #ifdef _KERNEL 669 /*ARGSUSED0*/ 670 tnf_uint32_t * 671 tnfw_b_fw_alloc(TNFW_B_WCB *wcb) 672 { 673 tnf_uint32_t *ret_val; 674 volatile tnf_buf_file_header_t *fh = 675 /* LINTED pointer cast may result in improper alignment */ 676 (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; 677 tnf_uint32_t *zone_end = (tnf_uint32_t *)((char *)fh + TNFW_B_FW_ZONE); 678 mutex_enter(&hintlock); 679 ret_val = (tnf_uint32_t *)((char *)fh + fh->next_fw_alloc); 680 if (ret_val != zone_end) 681 fh->next_fw_alloc += sizeof (tnf_uint32_t); 682 mutex_exit(&hintlock); 683 return ((ret_val != zone_end) ? ret_val : NULL); 684 } 685 686 #else 687 688 /*ARGSUSED0*/ 689 tnf_uint32_t * 690 tnfw_b_fw_alloc(TNFW_B_WCB *wcb) 691 { 692 volatile tnf_buf_file_header_t *fh = 693 /* LINTED pointer cast may result in improper alignment */ 694 (volatile tnf_buf_file_header_t *)_tnfw_b_control->tnf_buffer; 695 /* LINTED pointer cast may result in improper alignment */ 696 uint_t *hint = (uint_t *)((uintptr_t)fh + fh->next_fw_alloc); 697 /* LINTED pointer cast may result in improper alignment */ 698 ulong_t *zone_end = (ulong_t *)((uintptr_t)fh + TNFW_B_FW_ZONE); 699 u_long swapin; 700 char tmp_buf[512]; 701 tnf_uint32_t *retval; 702 703 #ifdef VERYVERBOSE 704 sprintf(tmp_buf, "tnfw_b_vw_alloc: begin\n"); 705 (void) write(2, tmp_buf, strlen(tmp_buf)); 706 #endif 707 708 #ifdef VERYVERBOSE 709 sprintf(tmp_buf, "tnfw_b_vw_alloc: (1)hint=%p\n", hint); 710 (void) write(2, tmp_buf, strlen(tmp_buf)); 711 #endif 712 713 while ((uintptr_t)hint != (uintptr_t)zone_end) { 714 #ifdef VERYVERBOSE 715 sprintf(tmp_buf, "tnfw_b_vw_alloc: (2)hint=%p,zone_end=%p\n", 716 hint, zone_end); 717 (void) write(2, tmp_buf, strlen(tmp_buf)); 718 #endif 719 720 #ifdef VERYVERBOSE 721 sprintf(tmp_buf, "tnfw_b_fw_alloc: fh = %p, next->alloc = %d\n", 722 fh, fh->next_fw_alloc); 723 (void) write(2, tmp_buf, strlen(tmp_buf)); 724 725 sprintf(tmp_buf, "tnfw_b_vw_alloc: about to deref hint\n"); 726 (void) write(2, tmp_buf, strlen(tmp_buf)); 727 728 sprintf(tmp_buf, "tnfw_b_vw_alloc: *hint=%ld\n", *hint); 729 (void) write(2, tmp_buf, strlen(tmp_buf)); 730 #endif 731 if (*hint == 0) { 732 swapin = tnfw_b_atomic_swap(hint, TNFW_B_FW_INVALID); 733 if (swapin != 0) { 734 if (swapin != (unsigned)TNFW_B_FW_INVALID) { 735 /* restore */ 736 *hint = swapin; 737 } 738 } else { 739 break; 740 } 741 } 742 ++hint; 743 #ifdef VERYVERBOSE 744 sprintf(tmp_buf, "tnfw_b_vw_alloc: (3)hint=%p\n", hint); 745 (void) write(2, tmp_buf, strlen(tmp_buf)); 746 #endif 747 748 } 749 /* LINTED pointer subtraction casted to 32 bits */ 750 fh->next_fw_alloc = (uint_t) ((char *)hint - (char *)fh); 751 retval = (((uintptr_t)hint != (uintptr_t)zone_end) ? 752 (tnf_uint32_t *)hint : NULL); 753 754 #ifdef VERYVERBOSE 755 sprintf(tmp_buf, "tnfw_b_vw_alloc: returning %p", retval); 756 (void) write(2, tmp_buf, strlen(tmp_buf)); 757 #endif 758 759 return (retval); 760 } 761 762 #endif /* _KERNEL */ 763