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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/ksynch.h> 28 #include <sys/cmn_err.h> 29 #include <sys/errno.h> 30 #include <sys/kmem.h> 31 #include <sys/cred.h> 32 #include <sys/buf.h> 33 #include <sys/ddi.h> 34 35 #include <sys/nsc_thread.h> 36 #include <sys/nsctl/nsctl.h> 37 38 #include <sys/sdt.h> /* dtrace is S10 or later */ 39 40 #include "sd_bcache.h" 41 #include "sd_trace.h" 42 #include "sd_io.h" 43 #include "sd_bio.h" 44 #include "sd_ft.h" 45 #include "sd_misc.h" 46 #include "sd_pcu.h" 47 48 #include <sys/unistat/spcs_s.h> 49 #include <sys/unistat/spcs_s_k.h> 50 #include <sys/unistat/spcs_errors.h> 51 #include <sys/nsctl/safestore.h> 52 #ifndef DS_DDICT 53 #include <sys/ddi_impldefs.h> 54 #endif 55 56 57 /* 58 * kstat interface 59 */ 60 61 static kstat_t *sdbc_global_stats_kstat; 62 static int sdbc_global_stats_update(kstat_t *ksp, int rw); 63 64 typedef struct { 65 kstat_named_t ci_sdbc_count; 66 kstat_named_t ci_sdbc_loc_count; 67 kstat_named_t ci_sdbc_rdhits; 68 kstat_named_t ci_sdbc_rdmiss; 69 kstat_named_t ci_sdbc_wrhits; 70 kstat_named_t ci_sdbc_wrmiss; 71 kstat_named_t ci_sdbc_blksize; 72 kstat_named_t ci_sdbc_lru_blocks; 73 #ifdef DEBUG 74 kstat_named_t ci_sdbc_lru_noreq; 75 kstat_named_t ci_sdbc_lru_req; 76 #endif 77 kstat_named_t ci_sdbc_wlru_inq; 78 kstat_named_t ci_sdbc_cachesize; 79 kstat_named_t ci_sdbc_numblocks; 80 kstat_named_t ci_sdbc_num_shared; 81 kstat_named_t ci_sdbc_wrcancelns; 82 kstat_named_t ci_sdbc_destaged; 83 kstat_named_t ci_sdbc_nodehints; 84 } sdbc_global_stats_t; 85 86 static sdbc_global_stats_t sdbc_global_stats = { 87 {SDBC_GKSTAT_COUNT, KSTAT_DATA_ULONG}, 88 {SDBC_GKSTAT_LOC_COUNT, KSTAT_DATA_ULONG}, 89 {SDBC_GKSTAT_RDHITS, KSTAT_DATA_ULONG}, 90 {SDBC_GKSTAT_RDMISS, KSTAT_DATA_ULONG}, 91 {SDBC_GKSTAT_WRHITS, KSTAT_DATA_ULONG}, 92 {SDBC_GKSTAT_WRMISS, KSTAT_DATA_ULONG}, 93 {SDBC_GKSTAT_BLKSIZE, KSTAT_DATA_ULONG}, 94 {SDBC_GKSTAT_LRU_BLOCKS, KSTAT_DATA_ULONG}, 95 #ifdef DEBUG 96 {SDBC_GKSTAT_LRU_NOREQ, KSTAT_DATA_ULONG}, 97 {SDBC_GKSTAT_LRU_REQ, KSTAT_DATA_ULONG}, 98 #endif 99 {SDBC_GKSTAT_WLRU_INQ, KSTAT_DATA_ULONG}, 100 {SDBC_GKSTAT_CACHESIZE, KSTAT_DATA_ULONG}, 101 {SDBC_GKSTAT_NUMBLOCKS, KSTAT_DATA_ULONG}, 102 {SDBC_GKSTAT_NUM_SHARED, KSTAT_DATA_ULONG}, 103 {SDBC_GKSTAT_WRCANCELNS, KSTAT_DATA_ULONG}, 104 {SDBC_GKSTAT_DESTAGED, KSTAT_DATA_ULONG}, 105 {SDBC_GKSTAT_NODEHINTS, KSTAT_DATA_ULONG}, 106 }; 107 108 static kstat_t **sdbc_cd_kstats; 109 static kstat_t **sdbc_cd_io_kstats; 110 static kmutex_t *sdbc_cd_io_kstats_mutexes; 111 static kstat_t *sdbc_global_io_kstat; 112 static kmutex_t sdbc_global_io_kstat_mutex; 113 static int sdbc_cd_stats_update(kstat_t *ksp, int rw); 114 static int cd_kstat_add(int cd); 115 static int cd_kstat_remove(int cd); 116 117 typedef struct { 118 kstat_named_t ci_sdbc_vol_name; 119 kstat_named_t ci_sdbc_failed; 120 kstat_named_t ci_sdbc_cd; 121 kstat_named_t ci_sdbc_cache_read; 122 kstat_named_t ci_sdbc_cache_write; 123 kstat_named_t ci_sdbc_disk_read; 124 kstat_named_t ci_sdbc_disk_write; 125 kstat_named_t ci_sdbc_filesize; 126 kstat_named_t ci_sdbc_numdirty; 127 kstat_named_t ci_sdbc_numio; 128 kstat_named_t ci_sdbc_numfail; 129 kstat_named_t ci_sdbc_destaged; 130 kstat_named_t ci_sdbc_wrcancelns; 131 kstat_named_t ci_sdbc_cdhints; 132 } sdbc_cd_stats_t; 133 134 static sdbc_cd_stats_t sdbc_cd_stats = { 135 {SDBC_CDKSTAT_VOL_NAME, KSTAT_DATA_CHAR}, 136 {SDBC_CDKSTAT_FAILED, KSTAT_DATA_ULONG}, 137 {SDBC_CDKSTAT_CD, KSTAT_DATA_ULONG}, 138 {SDBC_CDKSTAT_CACHE_READ, KSTAT_DATA_ULONG}, 139 {SDBC_CDKSTAT_CACHE_WRITE, KSTAT_DATA_ULONG}, 140 {SDBC_CDKSTAT_DISK_READ, KSTAT_DATA_ULONG}, 141 {SDBC_CDKSTAT_DISK_WRITE, KSTAT_DATA_ULONG}, 142 #ifdef NSC_MULTI_TERABYTE 143 {SDBC_CDKSTAT_FILESIZE, KSTAT_DATA_UINT64}, 144 #else 145 {SDBC_CDKSTAT_FILESIZE, KSTAT_DATA_ULONG}, 146 #endif 147 {SDBC_CDKSTAT_NUMDIRTY, KSTAT_DATA_ULONG}, 148 {SDBC_CDKSTAT_NUMIO, KSTAT_DATA_ULONG}, 149 {SDBC_CDKSTAT_NUMFAIL, KSTAT_DATA_ULONG}, 150 {SDBC_CDKSTAT_DESTAGED, KSTAT_DATA_ULONG}, 151 {SDBC_CDKSTAT_WRCANCELNS, KSTAT_DATA_ULONG}, 152 {SDBC_CDKSTAT_CDHINTS, KSTAT_DATA_ULONG}, 153 }; 154 155 #ifdef DEBUG 156 /* 157 * dynmem kstat interface 158 */ 159 static kstat_t *sdbc_dynmem_kstat_dm; 160 static int simplect_dm; 161 static int sdbc_dynmem_kstat_update_dm(kstat_t *ksp, int rw); 162 163 typedef struct { 164 kstat_named_t ci_sdbc_monitor_dynmem; 165 kstat_named_t ci_sdbc_max_dyn_list; 166 kstat_named_t ci_sdbc_cache_aging_ct1; 167 kstat_named_t ci_sdbc_cache_aging_ct2; 168 kstat_named_t ci_sdbc_cache_aging_ct3; 169 kstat_named_t ci_sdbc_cache_aging_sec1; 170 kstat_named_t ci_sdbc_cache_aging_sec2; 171 kstat_named_t ci_sdbc_cache_aging_sec3; 172 kstat_named_t ci_sdbc_cache_aging_pcnt1; 173 kstat_named_t ci_sdbc_cache_aging_pcnt2; 174 kstat_named_t ci_sdbc_max_holds_pcnt; 175 176 kstat_named_t ci_sdbc_alloc_ct; 177 kstat_named_t ci_sdbc_dealloc_ct; 178 kstat_named_t ci_sdbc_history; 179 kstat_named_t ci_sdbc_nodatas; 180 kstat_named_t ci_sdbc_candidates; 181 kstat_named_t ci_sdbc_deallocs; 182 kstat_named_t ci_sdbc_hosts; 183 kstat_named_t ci_sdbc_pests; 184 kstat_named_t ci_sdbc_metas; 185 kstat_named_t ci_sdbc_holds; 186 kstat_named_t ci_sdbc_others; 187 kstat_named_t ci_sdbc_notavail; 188 189 kstat_named_t ci_sdbc_process_directive; 190 191 kstat_named_t ci_sdbc_simplect; 192 } sdbc_dynmem_dm_t; 193 194 static sdbc_dynmem_dm_t sdbc_dynmem_dm = { 195 {SDBC_DMKSTAT_MONITOR_DYNMEM, KSTAT_DATA_ULONG}, 196 {SDBC_DMKSTAT_MAX_DYN_LIST, KSTAT_DATA_ULONG}, 197 {SDBC_DMKSTAT_CACHE_AGING_CT1, KSTAT_DATA_ULONG}, 198 {SDBC_DMKSTAT_CACHE_AGING_CT2, KSTAT_DATA_ULONG}, 199 {SDBC_DMKSTAT_CACHE_AGING_CT3, KSTAT_DATA_ULONG}, 200 {SDBC_DMKSTAT_CACHE_AGING_SEC1, KSTAT_DATA_ULONG}, 201 {SDBC_DMKSTAT_CACHE_AGING_SEC2, KSTAT_DATA_ULONG}, 202 {SDBC_DMKSTAT_CACHE_AGING_SEC3, KSTAT_DATA_ULONG}, 203 {SDBC_DMKSTAT_CACHE_AGING_PCNT1, KSTAT_DATA_ULONG}, 204 {SDBC_DMKSTAT_CACHE_AGING_PCNT2, KSTAT_DATA_ULONG}, 205 {SDBC_DMKSTAT_MAX_HOLDS_PCNT, KSTAT_DATA_ULONG}, 206 {SDBC_DMKSTAT_ALLOC_CNT, KSTAT_DATA_ULONG}, 207 {SDBC_DMKSTAT_DEALLOC_CNT, KSTAT_DATA_ULONG}, 208 {SDBC_DMKSTAT_HISTORY, KSTAT_DATA_ULONG}, 209 {SDBC_DMKSTAT_NODATAS, KSTAT_DATA_ULONG}, 210 {SDBC_DMKSTAT_CANDIDATES, KSTAT_DATA_ULONG}, 211 {SDBC_DMKSTAT_DEALLOCS, KSTAT_DATA_ULONG}, 212 {SDBC_DMKSTAT_HOSTS, KSTAT_DATA_ULONG}, 213 {SDBC_DMKSTAT_PESTS, KSTAT_DATA_ULONG}, 214 {SDBC_DMKSTAT_METAS, KSTAT_DATA_ULONG}, 215 {SDBC_DMKSTAT_HOLDS, KSTAT_DATA_ULONG}, 216 {SDBC_DMKSTAT_OTHERS, KSTAT_DATA_ULONG}, 217 {SDBC_DMKSTAT_NOTAVAIL, KSTAT_DATA_ULONG}, 218 {SDBC_DMKSTAT_PROCESS_DIRECTIVE, KSTAT_DATA_ULONG}, 219 {SDBC_DMKSTAT_SIMPLECT, KSTAT_DATA_ULONG} 220 }; 221 #endif 222 223 /* End of dynmem kstats */ 224 225 #ifdef DEBUG 226 int *dmchainpull_table; /* dmchain wastage stats */ 227 #endif 228 229 /* 230 * dynmem process vars 231 */ 232 extern _dm_process_vars_t dynmem_processing_dm; 233 234 /* metadata for volumes */ 235 ss_voldata_t *_sdbc_gl_file_info; 236 237 size_t _sdbc_gl_file_info_size; 238 239 /* metadata for cache write blocks */ 240 static ss_centry_info_t *_sdbc_gl_centry_info; 241 242 /* wblocks * sizeof(ss_centry_info_t) */ 243 static size_t _sdbc_gl_centry_info_size; 244 245 static int _SD_DELAY_QUEUE = 1; 246 static int sdbc_allocb_inuse, sdbc_allocb_lost, sdbc_allocb_hit; 247 static int sdbc_allocb_pageio1, sdbc_allocb_pageio2; 248 static int sdbc_centry_hit, sdbc_centry_inuse, sdbc_centry_lost; 249 static int sdbc_dmchain_not_avail; 250 static int sdbc_allocb_deallocd; 251 static int sdbc_centry_deallocd; 252 static int sdbc_check_cot; 253 static int sdbc_ra_hash; /* 1-block read-ahead fails due to hash hit */ 254 static int sdbc_ra_none; /* 1-block read-ahead fails due to "would block" */ 255 256 257 /* 258 * Set the following variable to 1 to enable pagelist io mutual 259 * exclusion on all _sd_alloc_buf() operations. 260 * 261 * This is set to ON to prevent front end / back end races between new 262 * NSC_WRTHRU io operations coming in through _sd_alloc_buf(), and 263 * previously written data being flushed out to disk by the sdbc 264 * flusher at the back end. 265 * -- see bugtraq 4287564 266 * -- Simon Crosland, Mon Nov 8 16:34:09 GMT 1999 267 */ 268 static int sdbc_pageio_always = 1; 269 270 int sdbc_use_dmchain = 0; /* start time switch for dm chaining */ 271 int sdbc_prefetch1 = 1; /* do 1-block read-ahead */ 272 /* 273 * if sdbc_static_cache is 1 allocate all cache memory at startup. 274 * deallocate only at shutdown. 275 */ 276 int sdbc_static_cache = 1; 277 278 #ifdef DEBUG 279 /* 280 * Pagelist io mutual exclusion debug facility. 281 */ 282 #define SDBC_PAGEIO_OFF 0 /* no debug */ 283 #define SDBC_PAGEIO_RDEV 1 /* force NSC_PAGEIO for specified dev */ 284 #define SDBC_PAGEIO_RAND 2 /* randomly force NSC_PAGEIO */ 285 #define SDBC_PAGEIO_ALL 3 /* always force NSC_PAGEIO */ 286 static int sdbc_pageio_debug = SDBC_PAGEIO_OFF; 287 static dev_t sdbc_pageio_rdev = (dev_t)-1; 288 #endif 289 290 /* 291 * INF SD cache global data 292 */ 293 294 _sd_cd_info_t *_sd_cache_files; 295 _sd_stats_t *_sd_cache_stats; 296 kmutex_t _sd_cache_lock; 297 298 _sd_hash_table_t *_sd_htable; 299 _sd_queue_t _sd_lru_q; 300 301 _sd_cctl_t *_sd_cctl[_SD_CCTL_GROUPS]; 302 int _sd_cctl_groupsz; 303 304 _sd_net_t _sd_net_config; 305 306 extern krwlock_t sdbc_queue_lock; 307 308 unsigned int _sd_node_hint; 309 310 #define _SD_LRU_Q (&_sd_lru_q) 311 int BLK_FBAS; /* number of FBA's in a cache block */ 312 int CACHE_BLOCK_SIZE; /* size in bytes of a cache block */ 313 int CBLOCKS; 314 _sd_bitmap_t BLK_FBA_BITS; 315 static int sdbc_prefetch_valid_cnt; 316 static int sdbc_prefetch_busy_cnt; 317 static int sdbc_prefetch_trailing; 318 static int sdbc_prefetch_deallocd; 319 static int sdbc_prefetch_pageio1; 320 static int sdbc_prefetch_pageio2; 321 static int sdbc_prefetch_hit; 322 static int sdbc_prefetch_lost; 323 static int _sd_prefetch_opt = 1; /* 0 to disable & use _prefetch_sb_vec[] */ 324 static nsc_vec_t _prefetch_sb_vec[_SD_MAX_BLKS + 1]; 325 326 _sd_bitmap_t _fba_bits[] = { 327 0x0000, 0x0001, 0x0003, 0x0007, 328 0x000f, 0x001f, 0x003f, 0x007f, 329 0x00ff, 330 #if defined(_SD_8K_BLKSIZE) 331 0x01ff, 0x03ff, 0x07ff, 332 0x0fff, 0x1fff, 0x3fff, 0x7fff, 333 0xffff, 334 #endif 335 }; 336 337 338 static int _sd_ccsync_cnt = 256; 339 static _sd_cctl_sync_t *_sd_ccent_sync; 340 341 nsc_io_t *sdbc_io; 342 343 #ifdef _MULTI_DATAMODEL 344 _sd_stats32_t *_sd_cache_stats32 = NULL; 345 #endif 346 347 348 #ifdef DEBUG 349 int cmn_level = CE_PANIC; 350 #else 351 int cmn_level = CE_WARN; 352 #endif 353 354 /* 355 * Forward declare all statics that are used before defined to enforce 356 * parameter checking 357 * Some (if not all) of these could be removed if the code were reordered 358 */ 359 360 static void _sdbc_stats_deconfigure(void); 361 static int _sdbc_stats_configure(int cblocks); 362 static int _sdbc_lruq_configure(_sd_queue_t *); 363 static void _sdbc_lruq_deconfigure(void); 364 static int _sdbc_mem_configure(int cblocks, spcs_s_info_t kstatus); 365 static void _sdbc_mem_deconfigure(int cblocks); 366 static void _sd_ins_queue(_sd_queue_t *, _sd_cctl_t *centry); 367 static int _sd_flush_cd(int cd); 368 static int _sd_check_buffer_alloc(int cd, nsc_off_t fba_pos, nsc_size_t fba_len, 369 _sd_buf_handle_t **hp); 370 static int _sd_doread(_sd_buf_handle_t *handle, _sd_cctl_t *cc_ent, 371 nsc_off_t fba_pos, nsc_size_t fba_len, int flag); 372 static void _sd_async_read_ea(blind_t xhandle, nsc_off_t fba_pos, 373 nsc_size_t fba_len, int error); 374 static void _sd_async_write_ea(blind_t xhandle, nsc_off_t fba_pos, 375 nsc_size_t fba_len, int error); 376 static void _sd_queue_write(_sd_buf_handle_t *handle, nsc_off_t fba_pos, 377 nsc_size_t fba_len); 378 static int _sd_remote_store(_sd_cctl_t *cc_ent, nsc_off_t fba_pos, 379 nsc_size_t fba_len); 380 static int _sd_copy_direct(_sd_buf_handle_t *handle1, _sd_buf_handle_t *handle2, 381 nsc_off_t fba_pos1, nsc_off_t fba_pos2, nsc_size_t fba_len); 382 static int _sd_sync_write(_sd_buf_handle_t *handle, nsc_off_t fba_pos, 383 nsc_size_t fba_len, int flag); 384 static int _sd_sync_write2(_sd_buf_handle_t *wr_handle, nsc_off_t wr_st_pos, 385 nsc_size_t fba_len, int flag, _sd_buf_handle_t *rd_handle, 386 nsc_off_t rd_st_pos); 387 static int sdbc_fd_attach_cd(blind_t xcd); 388 static int sdbc_fd_detach_cd(blind_t xcd); 389 static int sdbc_fd_flush_cd(blind_t xcd); 390 static int _sdbc_gl_centry_configure(spcs_s_info_t); 391 static int _sdbc_gl_file_configure(spcs_s_info_t); 392 static void _sdbc_gl_centry_deconfigure(void); 393 static void _sdbc_gl_file_deconfigure(void); 394 static int sdbc_doread_prefetch(_sd_cctl_t *cc_ent, nsc_off_t fba_pos, 395 nsc_size_t fba_len); 396 static _sd_bitmap_t update_dirty(_sd_cctl_t *cc_ent, sdbc_cblk_fba_t st_off, 397 sdbc_cblk_fba_t st_len); 398 static int _sd_prefetch_buf(int cd, nsc_off_t fba_pos, nsc_size_t fba_len, 399 int flag, _sd_buf_handle_t *handle, int locked); 400 401 /* dynmem support */ 402 static int _sd_setup_category_on_type(_sd_cctl_t *header); 403 static int _sd_setup_mem_chaining(_sd_cctl_t *header, int flag); 404 405 static int sdbc_check_cctl_cot(_sd_cctl_t *); 406 407 static int sdbc_dmqueues_configure(); 408 static void sdbc_dmqueues_deconfigure(); 409 static _sd_cctl_t *sdbc_get_dmchain(int, int *, int); 410 static int sdbc_dmchain_avail(_sd_cctl_t *); 411 void sdbc_requeue_dmchain(_sd_queue_t *, _sd_cctl_t *, int, int); 412 static void sdbc_ins_dmqueue_back(_sd_queue_t *, _sd_cctl_t *); 413 void sdbc_ins_dmqueue_front(_sd_queue_t *, _sd_cctl_t *); 414 void sdbc_remq_dmchain(_sd_queue_t *, _sd_cctl_t *); 415 static void sdbc_clear_dmchain(_sd_cctl_t *, _sd_cctl_t *); 416 void sdbc_requeue_head_dm_try(_sd_cctl_t *); 417 static _sd_cctl_t *sdbc_alloc_dmc(int, nsc_off_t, nsc_size_t, int *, 418 sdbc_allocbuf_t *, int); 419 static _sd_cctl_t *sdbc_alloc_lru(int, nsc_off_t, int *, int); 420 static _sd_cctl_t *sdbc_alloc_from_dmchain(int, nsc_off_t, sdbc_allocbuf_t *, 421 int); 422 static void sdbc_centry_init_dm(_sd_cctl_t *); 423 static int sdbc_centry_memalloc_dm(_sd_cctl_t *, int, int); 424 static void sdbc_centry_alloc_end(sdbc_allocbuf_t *); 425 426 427 428 429 /* _SD_DEBUG */ 430 #if defined(_SD_DEBUG) || defined(DEBUG) 431 static int _sd_cctl_valid(_sd_cctl_t *); 432 #endif 433 434 static 435 nsc_def_t _sdbc_fd_def[] = { 436 "Attach", (uintptr_t)sdbc_fd_attach_cd, 0, 437 "Detach", (uintptr_t)sdbc_fd_detach_cd, 0, 438 "Flush", (uintptr_t)sdbc_fd_flush_cd, 0, 439 0, 0, 0 440 }; 441 442 443 /* 444 * _sdbc_cache_configure - initialize cache blocks, queues etc. 445 * 446 * ARGUMENTS: 447 * cblocks - Number of cache blocks 448 * 449 * RETURNS: 450 * 0 on success. 451 * SDBC_EENABLEFAIL or SDBC_EMEMCONFIG on failure. 452 * 453 */ 454 455 456 457 int 458 _sdbc_cache_configure(int cblocks, spcs_s_info_t kstatus) 459 { 460 CBLOCKS = cblocks; 461 462 _sd_cache_files = (_sd_cd_info_t *) 463 kmem_zalloc(sdbc_max_devs * sizeof (_sd_cd_info_t), 464 KM_SLEEP); 465 466 if (_sdbc_stats_configure(cblocks)) 467 return (SDBC_EENABLEFAIL); 468 469 if (sdbc_use_dmchain) { 470 if (sdbc_dmqueues_configure()) 471 return (SDBC_EENABLEFAIL); 472 } else { 473 if (_sdbc_lruq_configure(_SD_LRU_Q)) 474 return (SDBC_EENABLEFAIL); 475 } 476 477 478 if (_sdbc_mem_configure(cblocks, kstatus)) 479 return (SDBC_EMEMCONFIG); 480 481 CACHE_BLOCK_SIZE = BLK_SIZE(1); 482 BLK_FBAS = FBA_NUM(CACHE_BLOCK_SIZE); 483 BLK_FBA_BITS = _fba_bits[BLK_FBAS]; 484 485 sdbc_allocb_pageio1 = 0; 486 sdbc_allocb_pageio2 = 0; 487 sdbc_allocb_hit = 0; 488 sdbc_allocb_inuse = 0; 489 sdbc_allocb_lost = 0; 490 sdbc_centry_inuse = 0; 491 sdbc_centry_lost = 0; 492 sdbc_centry_hit = 0; 493 sdbc_centry_deallocd = 0; 494 sdbc_dmchain_not_avail = 0; 495 sdbc_allocb_deallocd = 0; 496 497 sdbc_prefetch_valid_cnt = 0; 498 sdbc_prefetch_busy_cnt = 0; 499 sdbc_prefetch_trailing = 0; 500 sdbc_prefetch_deallocd = 0; 501 sdbc_prefetch_pageio1 = 0; 502 sdbc_prefetch_pageio2 = 0; 503 sdbc_prefetch_hit = 0; 504 sdbc_prefetch_lost = 0; 505 506 sdbc_check_cot = 0; 507 sdbc_prefetch1 = 1; 508 sdbc_ra_hash = 0; 509 sdbc_ra_none = 0; 510 511 return (0); 512 } 513 514 /* 515 * _sdbc_cache_deconfigure - cache is being deconfigured. Release any 516 * memory that we acquired during the configuration process and return 517 * to the unconfigured state. 518 * 519 * NOTE: all users of the cache should be inactive at this point, 520 * i.e. we are unregistered from sd and all cache daemons/threads are 521 * gone. 522 * 523 */ 524 void 525 _sdbc_cache_deconfigure(void) 526 { 527 /* CCIO shutdown must happen before memory is free'd */ 528 529 if (_sd_cache_files) { 530 kmem_free(_sd_cache_files, 531 sdbc_max_devs * sizeof (_sd_cd_info_t)); 532 _sd_cache_files = (_sd_cd_info_t *)NULL; 533 } 534 535 536 BLK_FBA_BITS = 0; 537 BLK_FBAS = 0; 538 CACHE_BLOCK_SIZE = 0; 539 _sdbc_mem_deconfigure(CBLOCKS); 540 _sdbc_gl_centry_deconfigure(); 541 _sdbc_gl_file_deconfigure(); 542 543 if (sdbc_use_dmchain) 544 sdbc_dmqueues_deconfigure(); 545 else 546 _sdbc_lruq_deconfigure(); 547 _sdbc_stats_deconfigure(); 548 549 CBLOCKS = 0; 550 } 551 552 553 /* 554 * _sdbc_stats_deconfigure - cache is being deconfigured turn off 555 * stats. This could seemingly do more but we leave most of the 556 * data intact until cache is configured again. 557 * 558 */ 559 static void 560 _sdbc_stats_deconfigure(void) 561 { 562 int i; 563 564 #ifdef DEBUG 565 if (sdbc_dynmem_kstat_dm) { 566 kstat_delete(sdbc_dynmem_kstat_dm); 567 sdbc_dynmem_kstat_dm = NULL; 568 } 569 #endif 570 571 if (sdbc_global_stats_kstat) { 572 kstat_delete(sdbc_global_stats_kstat); 573 sdbc_global_stats_kstat = NULL; 574 } 575 576 if (sdbc_cd_kstats) { 577 for (i = 0; i < sdbc_max_devs; i++) { 578 if (sdbc_cd_kstats[i]) { 579 kstat_delete(sdbc_cd_kstats[i]); 580 sdbc_cd_kstats[i] = NULL; 581 } 582 } 583 kmem_free(sdbc_cd_kstats, sizeof (kstat_t *) * sdbc_max_devs); 584 sdbc_cd_kstats = NULL; 585 } 586 587 if (sdbc_global_io_kstat) { 588 kstat_delete(sdbc_global_io_kstat); 589 mutex_destroy(&sdbc_global_io_kstat_mutex); 590 sdbc_global_io_kstat = NULL; 591 } 592 593 if (sdbc_cd_io_kstats) { 594 for (i = 0; i < sdbc_max_devs; i++) { 595 if (sdbc_cd_io_kstats[i]) { 596 kstat_delete(sdbc_cd_io_kstats[i]); 597 sdbc_cd_io_kstats[i] = NULL; 598 } 599 } 600 kmem_free(sdbc_cd_io_kstats, sizeof (kstat_t *) * 601 sdbc_max_devs); 602 sdbc_cd_io_kstats = NULL; 603 } 604 605 if (sdbc_cd_io_kstats_mutexes) { 606 /* mutexes are already destroyed in cd_kstat_remove() */ 607 kmem_free(sdbc_cd_io_kstats_mutexes, 608 sizeof (kmutex_t) * sdbc_max_devs); 609 sdbc_cd_io_kstats_mutexes = NULL; 610 } 611 612 613 if (_sd_cache_stats) { 614 kmem_free(_sd_cache_stats, 615 sizeof (_sd_stats_t) + 616 (sdbc_max_devs - 1) * sizeof (_sd_shared_t)); 617 _sd_cache_stats = NULL; 618 } 619 #ifdef _MULTI_DATAMODEL 620 if (_sd_cache_stats32) { 621 kmem_free(_sd_cache_stats32, sizeof (_sd_stats32_t) + 622 (sdbc_max_devs - 1) * sizeof (_sd_shared_t)); 623 _sd_cache_stats32 = NULL; 624 } 625 #endif 626 } 627 628 static int 629 _sdbc_stats_configure(int cblocks) 630 { 631 632 _sd_cache_stats = kmem_zalloc(sizeof (_sd_stats_t) + 633 (sdbc_max_devs - 1) * sizeof (_sd_shared_t), KM_SLEEP); 634 _sd_cache_stats->st_blksize = (int)BLK_SIZE(1); 635 _sd_cache_stats->st_cachesize = cblocks * BLK_SIZE(1); 636 _sd_cache_stats->st_numblocks = cblocks; 637 _sd_cache_stats->st_wrcancelns = 0; 638 _sd_cache_stats->st_destaged = 0; 639 #ifdef _MULTI_DATAMODEL 640 _sd_cache_stats32 = kmem_zalloc(sizeof (_sd_stats32_t) + 641 (sdbc_max_devs - 1) * sizeof (_sd_shared_t), KM_SLEEP); 642 #endif 643 644 /* kstat implementation - global stats */ 645 sdbc_global_stats_kstat = kstat_create(SDBC_KSTAT_MODULE, 0, 646 SDBC_KSTAT_GSTATS, SDBC_KSTAT_CLASS, KSTAT_TYPE_NAMED, 647 sizeof (sdbc_global_stats)/sizeof (kstat_named_t), 648 KSTAT_FLAG_VIRTUAL|KSTAT_FLAG_WRITABLE); 649 650 if (sdbc_global_stats_kstat != NULL) { 651 sdbc_global_stats_kstat->ks_data = &sdbc_global_stats; 652 sdbc_global_stats_kstat->ks_update = sdbc_global_stats_update; 653 sdbc_global_stats_kstat->ks_private = _sd_cache_stats; 654 kstat_install(sdbc_global_stats_kstat); 655 } else { 656 cmn_err(CE_WARN, "!sdbc: gstats kstat failed"); 657 } 658 659 /* global I/O kstats */ 660 sdbc_global_io_kstat = kstat_create(SDBC_KSTAT_MODULE, 0, 661 SDBC_IOKSTAT_GSTATS, "disk", KSTAT_TYPE_IO, 1, 0); 662 663 if (sdbc_global_io_kstat) { 664 mutex_init(&sdbc_global_io_kstat_mutex, NULL, MUTEX_DRIVER, 665 NULL); 666 sdbc_global_io_kstat->ks_lock = 667 &sdbc_global_io_kstat_mutex; 668 kstat_install(sdbc_global_io_kstat); 669 } 670 671 /* 672 * kstat implementation - cd stats 673 * NOTE: one kstat instance for each open cache descriptor 674 */ 675 sdbc_cd_kstats = kmem_zalloc(sizeof (kstat_t *) * sdbc_max_devs, 676 KM_SLEEP); 677 678 /* 679 * kstat implementation - i/o kstats per cache descriptor 680 * NOTE: one I/O kstat instance for each cd 681 */ 682 sdbc_cd_io_kstats = kmem_zalloc(sizeof (kstat_t *) * sdbc_max_devs, 683 KM_SLEEP); 684 685 sdbc_cd_io_kstats_mutexes = kmem_zalloc(sizeof (kmutex_t) * 686 sdbc_max_devs, KM_SLEEP); 687 688 #ifdef DEBUG 689 /* kstat implementation - dynamic memory stats */ 690 sdbc_dynmem_kstat_dm = kstat_create(SDBC_KSTAT_MODULE, 0, 691 SDBC_KSTAT_DYNMEM, SDBC_KSTAT_CLASS, KSTAT_TYPE_NAMED, 692 sizeof (sdbc_dynmem_dm)/sizeof (kstat_named_t), 693 KSTAT_FLAG_VIRTUAL|KSTAT_FLAG_WRITABLE); 694 695 if (sdbc_dynmem_kstat_dm != NULL) { 696 sdbc_dynmem_kstat_dm->ks_data = &sdbc_dynmem_dm; 697 sdbc_dynmem_kstat_dm->ks_update = sdbc_dynmem_kstat_update_dm; 698 sdbc_dynmem_kstat_dm->ks_private = &dynmem_processing_dm; 699 kstat_install(sdbc_dynmem_kstat_dm); 700 } else { 701 cmn_err(CE_WARN, "!sdbc: dynmem kstat failed"); 702 } 703 #endif 704 705 return (0); 706 } 707 708 /* 709 * sdbc_dmqueues_configure() 710 * initialize the queues of dynamic memory chains. 711 */ 712 713 _sd_queue_t *sdbc_dm_queues; 714 static int max_dm_queues; 715 716 717 static int 718 sdbc_dmqueues_configure() 719 { 720 int i; 721 722 /* 723 * CAUTION! this code depends on max_dyn_list not changing 724 * if it does change behavior may be incorrect, as cc_alloc_size_dm 725 * depends on max_dyn_list and indexes to dmqueues are derived from 726 * cc_alloc_size_dm. 727 * see _sd_setup_category_on_type() and _sd_dealloc_dm() 728 * TODO: prevent max_dyn_list from on-the-fly modification (easy) or 729 * allow for on-the-fly changes to number of dm queues (hard). 730 */ 731 max_dm_queues = dynmem_processing_dm.max_dyn_list; 732 733 ++max_dm_queues; /* need a "0" queue for centrys with no memory */ 734 735 sdbc_dm_queues = (_sd_queue_t *) 736 kmem_zalloc(max_dm_queues * sizeof (_sd_queue_t), KM_SLEEP); 737 738 #ifdef DEBUG 739 dmchainpull_table = (int *)kmem_zalloc(max_dm_queues * 740 max_dm_queues * sizeof (int), KM_SLEEP); 741 #endif 742 743 for (i = 0; i < max_dm_queues; ++i) { 744 (void) _sdbc_lruq_configure(&sdbc_dm_queues[i]); 745 sdbc_dm_queues[i].sq_dmchain_cblocks = i; 746 } 747 748 return (0); 749 } 750 751 static void 752 sdbc_dmqueues_deconfigure() 753 { 754 /* CAUTION! this code depends on max_dyn_list not changing */ 755 756 if (sdbc_dm_queues) 757 kmem_free(sdbc_dm_queues, max_dm_queues * sizeof (_sd_queue_t)); 758 sdbc_dm_queues = NULL; 759 max_dm_queues = 0; 760 } 761 762 #define GOOD_LRUSIZE(q) ((q->sq_inq >= 0) || (q->sq_inq <= CBLOCKS)) 763 764 /* 765 * _sdbc_lruq_configure - initialize the lru queue 766 * 767 * ARGUMENTS: NONE 768 * RETURNS: 0 769 * 770 */ 771 772 static int 773 _sdbc_lruq_configure(_sd_queue_t *_sd_lru) 774 { 775 776 _sd_lru->sq_inq = 0; 777 778 mutex_init(&_sd_lru->sq_qlock, NULL, MUTEX_DRIVER, NULL); 779 780 _sd_lru->sq_qhead.cc_next = _sd_lru->sq_qhead.cc_prev 781 = &(_sd_lru->sq_qhead); 782 return (0); 783 } 784 785 /* 786 * _sdbc_lruq_deconfigure - deconfigure the lru queue 787 * 788 * ARGUMENTS: NONE 789 * 790 */ 791 792 static void 793 _sdbc_lruq_deconfigure(void) 794 { 795 _sd_queue_t *_sd_lru; 796 797 _sd_lru = _SD_LRU_Q; 798 799 mutex_destroy(&_sd_lru->sq_qlock); 800 bzero(_sd_lru, sizeof (_sd_queue_t)); 801 802 } 803 804 /* 805 * _sdbc_mem_configure - initialize the cache memory. 806 * Create and initialize the hash table. 807 * Create cache control blocks and fill them with relevent 808 * information and enqueue onto the lru queue. 809 * Initialize the Write control blocks (blocks that contain 810 * information as to where the data will be mirrored) 811 * Initialize the Fault tolerant blocks (blocks that contain 812 * information about the mirror nodes dirty writes) 813 * 814 * ARGUMENTS: 815 * cblocks - Number of cache blocks. 816 * RETURNS: 0 817 * 818 */ 819 static int 820 _sdbc_mem_configure(int cblocks, spcs_s_info_t kstatus) 821 { 822 int num_blks, i, blk; 823 _sd_cctl_t *centry; 824 _sd_net_t *netc; 825 _sd_cctl_t *prev_entry_dm, *first_entry_dm; 826 827 if ((_sd_htable = _sdbc_hash_configure(cblocks)) == NULL) { 828 spcs_s_add(kstatus, SDBC_ENOHASH); 829 return (-1); 830 } 831 832 _sd_cctl_groupsz = (cblocks / _SD_CCTL_GROUPS) + 833 ((cblocks % _SD_CCTL_GROUPS) != 0); 834 835 for (i = 0; i < _SD_CCTL_GROUPS; i++) { 836 _sd_cctl[i] = (_sd_cctl_t *) 837 nsc_kmem_zalloc(_sd_cctl_groupsz * sizeof (_sd_cctl_t), 838 KM_SLEEP, sdbc_cache_mem); 839 840 if (_sd_cctl[i] == NULL) { 841 spcs_s_add(kstatus, SDBC_ENOCB); 842 return (-1); 843 } 844 } 845 846 _sd_ccent_sync = (_sd_cctl_sync_t *) 847 nsc_kmem_zalloc(_sd_ccsync_cnt * sizeof (_sd_cctl_sync_t), 848 KM_SLEEP, sdbc_local_mem); 849 850 if (_sd_ccent_sync == NULL) { 851 spcs_s_add(kstatus, SDBC_ENOCCTL); 852 return (-1); 853 } 854 855 for (i = 0; i < _sd_ccsync_cnt; i++) { 856 mutex_init(&_sd_ccent_sync[i]._cc_lock, NULL, MUTEX_DRIVER, 857 NULL); 858 cv_init(&_sd_ccent_sync[i]._cc_blkcv, NULL, CV_DRIVER, NULL); 859 } 860 861 blk = 0; 862 863 netc = &_sd_net_config; 864 865 num_blks = (netc->sn_cpages * (int)netc->sn_psize)/BLK_SIZE(1); 866 867 prev_entry_dm = 0; 868 first_entry_dm = 0; 869 for (i = 0; i < num_blks; i++, blk++) { 870 centry = _sd_cctl[(blk/_sd_cctl_groupsz)] + 871 (blk%_sd_cctl_groupsz); 872 centry->cc_sync = &_sd_ccent_sync[blk % _sd_ccsync_cnt]; 873 centry->cc_next = centry->cc_prev = NULL; 874 centry->cc_dirty_next = centry->cc_dirty_link = NULL; 875 centry->cc_await_use = centry->cc_await_page = 0; 876 centry->cc_inuse = centry->cc_pageio = 0; 877 centry->cc_flag = 0; 878 centry->cc_iocount = 0; 879 centry->cc_valid = 0; 880 881 if (!first_entry_dm) 882 first_entry_dm = centry; 883 if (prev_entry_dm) 884 prev_entry_dm->cc_link_list_dm = centry; 885 prev_entry_dm = centry; 886 centry->cc_link_list_dm = first_entry_dm; 887 centry->cc_data = 0; 888 centry->cc_write = NULL; 889 centry->cc_dirty = 0; 890 891 { 892 _sd_queue_t *q; 893 if (sdbc_use_dmchain) { 894 q = &sdbc_dm_queues[0]; 895 centry->cc_cblocks = 0; 896 } else 897 q = _SD_LRU_Q; 898 899 _sd_ins_queue(q, centry); 900 } 901 902 } 903 904 if (_sdbc_gl_centry_configure(kstatus) != 0) 905 return (-1); 906 907 if (_sdbc_gl_file_configure(kstatus) != 0) 908 return (-1); 909 910 return (0); 911 } 912 913 /* 914 * _sdbc_gl_file_configure() 915 * allocate and initialize space for the global filename data. 916 * 917 */ 918 static int 919 _sdbc_gl_file_configure(spcs_s_info_t kstatus) 920 { 921 ss_voldata_t *fileinfo; 922 ss_voldata_t tempfinfo; 923 ss_vdir_t vdir; 924 ss_vdirkey_t key; 925 int err = 0; 926 927 _sdbc_gl_file_info_size = safestore_config.ssc_maxfiles * 928 sizeof (ss_voldata_t); 929 930 if ((_sdbc_gl_file_info = kmem_zalloc(_sdbc_gl_file_info_size, 931 KM_NOSLEEP)) == NULL) { 932 spcs_s_add(kstatus, SDBC_ENOSFNV); 933 return (-1); 934 } 935 936 /* setup the key to get a directory stream of all volumes */ 937 key.vk_type = CDIR_ALL; 938 939 fileinfo = _sdbc_gl_file_info; 940 941 /* 942 * if coming up after a crash, "refresh" the host 943 * memory copy from safestore. 944 */ 945 if (_sdbc_warm_start()) { 946 947 if (SSOP_GETVDIR(sdbc_safestore, &key, &vdir)) { 948 cmn_err(CE_WARN, "!sdbc(_sdbc_gl_file_configure): " 949 "cannot read safestore"); 950 return (-1); 951 } 952 953 954 /* 955 * cycle through the vdir getting volume data 956 * and volume tokens 957 */ 958 959 while ((err = SSOP_GETVDIRENT(sdbc_safestore, &vdir, fileinfo)) 960 == SS_OK) { 961 ++fileinfo; 962 } 963 964 if (err != SS_EOF) { 965 /* 966 * fail to configure since 967 * recovery is not possible. 968 */ 969 spcs_s_add(kstatus, SDBC_ENOREFRESH); 970 return (-1); 971 } 972 973 } else { /* normal initialization, not a warm start */ 974 975 /* 976 * if this fails, continue: cache will start 977 * in writethru mode 978 */ 979 980 if (SSOP_GETVDIR(sdbc_safestore, &key, &vdir)) { 981 cmn_err(CE_WARN, "!sdbc(_sdbc_gl_file_configure): " 982 "cannot read safestore"); 983 return (-1); 984 } 985 986 /* 987 * cycle through the vdir getting just the volume tokens 988 * and initializing volume entries 989 */ 990 991 while ((err = SSOP_GETVDIRENT(sdbc_safestore, &vdir, 992 &tempfinfo)) == 0) { 993 /* 994 * initialize the host memory copy of the 995 * global file region. this means setting the 996 * _pinned and _attached fields to _SD_NO_HOST 997 * because the default of zero conflicts with 998 * the min nodeid of zero. 999 */ 1000 fileinfo->sv_vol = tempfinfo.sv_vol; 1001 fileinfo->sv_pinned = _SD_NO_HOST; 1002 fileinfo->sv_attached = _SD_NO_HOST; 1003 fileinfo->sv_cd = _SD_NO_CD; 1004 1005 /* initialize the directory entry */ 1006 if ((err = SSOP_SETVOL(sdbc_safestore, fileinfo)) 1007 == SS_ERR) { 1008 cmn_err(CE_WARN, 1009 "!sdbc(_sdbc_gl_file_configure): " 1010 "volume entry write failure %p", 1011 (void *)fileinfo->sv_vol); 1012 break; 1013 } 1014 1015 ++fileinfo; 1016 } 1017 1018 /* coming up clean, continue in w-t mode */ 1019 if (err != SS_EOF) 1020 cmn_err(CE_WARN, "!sdbc(_sdbc_gl_file_configure) " 1021 "unable to init safe store volinfo"); 1022 } 1023 1024 return (0); 1025 } 1026 1027 static void 1028 _sdbc_gl_centry_deconfigure(void) 1029 { 1030 if (_sdbc_gl_centry_info) 1031 kmem_free(_sdbc_gl_centry_info, _sdbc_gl_centry_info_size); 1032 1033 _sdbc_gl_centry_info = NULL; 1034 _sdbc_gl_centry_info_size = 0; 1035 } 1036 1037 static int 1038 _sdbc_gl_centry_configure(spcs_s_info_t kstatus) 1039 { 1040 1041 int wblocks; 1042 ss_centry_info_t *cinfo; 1043 ss_cdirkey_t key; 1044 ss_cdir_t cdir; 1045 int err = 0; 1046 1047 1048 wblocks = safestore_config.ssc_wsize / BLK_SIZE(1); 1049 _sdbc_gl_centry_info_size = sizeof (ss_centry_info_t) * wblocks; 1050 1051 if ((_sdbc_gl_centry_info = kmem_zalloc(_sdbc_gl_centry_info_size, 1052 KM_NOSLEEP)) == NULL) { 1053 cmn_err(CE_WARN, "!sdbc(_sdbc_gl_centry_configure) " 1054 "alloc failed for gl_centry_info region"); 1055 1056 _sdbc_gl_centry_deconfigure(); 1057 return (-1); 1058 } 1059 1060 /* 1061 * synchronize the centry info area with safe store 1062 */ 1063 1064 /* setup the key to get a directory stream of all centrys */ 1065 key.ck_type = CDIR_ALL; 1066 1067 cinfo = _sdbc_gl_centry_info; 1068 1069 if (_sdbc_warm_start()) { 1070 1071 if (SSOP_GETCDIR(sdbc_safestore, &key, &cdir)) { 1072 cmn_err(CE_WARN, "!sdbc(_sdbc_gl_centry_configure): " 1073 "cannot read safestore"); 1074 return (-1); 1075 } 1076 1077 1078 /* 1079 * cycle through the cdir getting resource 1080 * tokens and reading centrys 1081 */ 1082 1083 while ((err = SSOP_GETCDIRENT(sdbc_safestore, &cdir, cinfo)) 1084 == 0) { 1085 ++cinfo; 1086 } 1087 1088 if (err != SS_EOF) { 1089 /* 1090 * fail to configure since 1091 * recovery is not possible. 1092 */ 1093 _sdbc_gl_centry_deconfigure(); 1094 spcs_s_add(kstatus, SDBC_EGLDMAFAIL); 1095 return (-1); 1096 } 1097 1098 } else { 1099 1100 if (SSOP_GETCDIR(sdbc_safestore, &key, &cdir)) { 1101 cmn_err(CE_WARN, "!sdbc(_sdbc_gl_centry_configure): " 1102 "cannot read safestore"); 1103 return (-1); 1104 } 1105 1106 /* 1107 * cycle through the cdir getting resource 1108 * tokens and initializing centrys 1109 */ 1110 1111 while ((err = SSOP_GETCDIRENT(sdbc_safestore, &cdir, cinfo)) 1112 == 0) { 1113 cinfo->sc_cd = -1; 1114 cinfo->sc_fpos = -1; 1115 1116 if ((err = SSOP_SETCENTRY(sdbc_safestore, cinfo)) 1117 == SS_ERR) { 1118 cmn_err(CE_WARN, 1119 "!sdbc(_sdbc_gl_centry_configure): " 1120 "cache entry write failure %p", 1121 (void *)cinfo->sc_res); 1122 break; 1123 } 1124 1125 ++cinfo; 1126 } 1127 1128 /* coming up clean, continue in w-t mode */ 1129 if (err != SS_EOF) { 1130 cmn_err(CE_WARN, "!sdbc(sdbc_gl_centry_configure) " 1131 "_sdbc_gl_centry_info initialization failed"); 1132 } 1133 } 1134 1135 return (0); 1136 } 1137 1138 1139 static void 1140 _sdbc_gl_file_deconfigure(void) 1141 { 1142 1143 if (_sdbc_gl_file_info) 1144 kmem_free(_sdbc_gl_file_info, _sdbc_gl_file_info_size); 1145 1146 _sdbc_gl_file_info = NULL; 1147 1148 _sdbc_gl_file_info_size = 0; 1149 } 1150 1151 1152 /* 1153 * _sdbc_mem_deconfigure - deconfigure the cache memory. 1154 * Release any memory/locks/sv's acquired during _sdbc_mem_configure. 1155 * 1156 * ARGUMENTS: 1157 * cblocks - Number of cache blocks. 1158 * 1159 */ 1160 /* ARGSUSED */ 1161 static void 1162 _sdbc_mem_deconfigure(int cblocks) 1163 { 1164 int i; 1165 1166 if (_sd_ccent_sync) { 1167 for (i = 0; i < _sd_ccsync_cnt; i++) { 1168 mutex_destroy(&_sd_ccent_sync[i]._cc_lock); 1169 cv_destroy(&_sd_ccent_sync[i]._cc_blkcv); 1170 } 1171 nsc_kmem_free(_sd_ccent_sync, 1172 _sd_ccsync_cnt * sizeof (_sd_cctl_sync_t)); 1173 } 1174 _sd_ccent_sync = NULL; 1175 1176 for (i = 0; i < _SD_CCTL_GROUPS; i++) { 1177 if (_sd_cctl[i] != NULL) { 1178 nsc_kmem_free(_sd_cctl[i], 1179 _sd_cctl_groupsz * sizeof (_sd_cctl_t)); 1180 _sd_cctl[i] = NULL; 1181 } 1182 } 1183 _sd_cctl_groupsz = 0; 1184 1185 _sdbc_hash_deconfigure(_sd_htable); 1186 _sd_htable = NULL; 1187 1188 } 1189 1190 1191 #if defined(_SD_DEBUG) || defined(DEBUG) 1192 static int 1193 _sd_cctl_valid(_sd_cctl_t *addr) 1194 { 1195 _sd_cctl_t *end; 1196 int i, valid; 1197 1198 valid = 0; 1199 for (i = 0; i < _SD_CCTL_GROUPS; i++) { 1200 end = _sd_cctl[i] + _sd_cctl_groupsz; 1201 if (addr >= _sd_cctl[i] && addr < end) { 1202 valid = 1; 1203 break; 1204 } 1205 } 1206 1207 return (valid); 1208 } 1209 #endif 1210 1211 1212 /* 1213 * _sd_ins_queue - insert centry into LRU queue 1214 * (during initialization, locking not required) 1215 */ 1216 static void 1217 _sd_ins_queue(_sd_queue_t *q, _sd_cctl_t *centry) 1218 { 1219 _sd_cctl_t *q_head; 1220 1221 ASSERT(_sd_cctl_valid(centry)); 1222 1223 q_head = &q->sq_qhead; 1224 centry->cc_prev = q_head; 1225 centry->cc_next = q_head->cc_next; 1226 q_head->cc_next->cc_prev = centry; 1227 q_head->cc_next = centry; 1228 q->sq_inq++; 1229 1230 ASSERT(GOOD_LRUSIZE(q)); 1231 } 1232 1233 1234 1235 void 1236 _sd_requeue(_sd_cctl_t *centry) 1237 { 1238 _sd_queue_t *q = _SD_LRU_Q; 1239 1240 /* was FAST */ 1241 mutex_enter(&q->sq_qlock); 1242 #if defined(_SD_DEBUG) 1243 if (1) { 1244 _sd_cctl_t *cp, *cn, *qp; 1245 cp = centry->cc_prev; 1246 cn = centry->cc_next; 1247 qp = (q->sq_qhead).cc_prev; 1248 if (!_sd_cctl_valid(centry) || 1249 (cp != &(q->sq_qhead) && !_sd_cctl_valid(cp)) || 1250 (cn != &(q->sq_qhead) && !_sd_cctl_valid(cn)) || 1251 !_sd_cctl_valid(qp)) 1252 cmn_err(CE_PANIC, 1253 "_sd_requeue %x prev %x next %x qp %x", 1254 centry, cp, cn, qp); 1255 } 1256 #endif 1257 centry->cc_prev->cc_next = centry->cc_next; 1258 centry->cc_next->cc_prev = centry->cc_prev; 1259 centry->cc_next = &(q->sq_qhead); 1260 centry->cc_prev = q->sq_qhead.cc_prev; 1261 q->sq_qhead.cc_prev->cc_next = centry; 1262 q->sq_qhead.cc_prev = centry; 1263 centry->cc_seq = q->sq_seq++; 1264 /* was FAST */ 1265 mutex_exit(&q->sq_qlock); 1266 (q->sq_req_stat)++; 1267 1268 } 1269 1270 void 1271 _sd_requeue_head(_sd_cctl_t *centry) 1272 { 1273 _sd_queue_t *q = _SD_LRU_Q; 1274 1275 /* was FAST */ 1276 mutex_enter(&q->sq_qlock); 1277 #if defined(_SD_DEBUG) 1278 if (1) { 1279 _sd_cctl_t *cp, *cn, *qn; 1280 cp = centry->cc_prev; 1281 cn = centry->cc_next; 1282 qn = (q->sq_qhead).cc_prev; 1283 if (!_sd_cctl_valid(centry) || 1284 (cp != &(q->sq_qhead) && !_sd_cctl_valid(cp)) || 1285 (cn != &(q->sq_qhead) && !_sd_cctl_valid(cn)) || 1286 !_sd_cctl_valid(qn)) 1287 cmn_err(CE_PANIC, 1288 "_sd_requeue_head %x prev %x next %x qn %x", 1289 centry, cp, cn, qn); 1290 } 1291 #endif 1292 centry->cc_prev->cc_next = centry->cc_next; 1293 centry->cc_next->cc_prev = centry->cc_prev; 1294 centry->cc_prev = &(q->sq_qhead); 1295 centry->cc_next = q->sq_qhead.cc_next; 1296 q->sq_qhead.cc_next->cc_prev = centry; 1297 q->sq_qhead.cc_next = centry; 1298 centry->cc_seq = q->sq_seq++; 1299 centry->cc_flag &= ~CC_QHEAD; 1300 /* was FAST */ 1301 mutex_exit(&q->sq_qlock); 1302 } 1303 1304 1305 1306 /* 1307 * _sd_open - Open a file. 1308 * 1309 * ARGUMENTS: 1310 * filename - Name of the file to be opened. 1311 * flag - Flag associated with open. 1312 * (currently used to determine a ckd device) 1313 * RETURNS: 1314 * cd - the cache descriptor. 1315 */ 1316 1317 int 1318 _sd_open(char *filename, int flag) 1319 { 1320 int cd; 1321 1322 if (!_sd_cache_initialized) { 1323 cmn_err(CE_WARN, "!sdbc(_sd_open) cache not initialized"); 1324 return (-EINVAL); 1325 } 1326 cd = _sd_open_cd(filename, -1, flag); 1327 SDTRACE(SDF_OPEN, (cd < 0) ? SDT_INV_CD : cd, 0, SDT_INV_BL, 0, cd); 1328 1329 return (cd); 1330 } 1331 1332 1333 static int 1334 _sd_open_io(char *filename, int flag, blind_t *cdp, nsc_iodev_t *iodev) 1335 { 1336 _sd_cd_info_t *cdi; 1337 int cd; 1338 int rc = 0; 1339 1340 if ((cd = _sd_open(filename, flag)) >= 0) { 1341 1342 cdi = &(_sd_cache_files[cd]); 1343 cdi->cd_iodev = iodev; 1344 nsc_set_owner(cdi->cd_rawfd, cdi->cd_iodev); 1345 1346 *cdp = (blind_t)(unsigned long)cd; 1347 } else 1348 rc = -cd; 1349 1350 return (rc); 1351 } 1352 1353 1354 1355 int 1356 _sd_open_cd(char *filename, const int cd, const int flag) 1357 { 1358 int new_cd, rc = 0, alloc_cd = -1; 1359 ss_voldata_t *cdg; 1360 int preexists = 0; 1361 _sd_cd_info_t *cdi; 1362 int failover_open, open_failed; 1363 major_t devmaj; 1364 minor_t devmin; 1365 1366 if (_sdbc_shutdown_in_progress) 1367 return (-EIO); 1368 1369 if (strlen(filename) > (NSC_MAXPATH-1)) 1370 return (-ENAMETOOLONG); 1371 1372 /* 1373 * If the cd is >= 0, then this is a open for a specific cd. 1374 * This happens when the mirror node crashes, and we attempt to 1375 * reopen the files with the same cache descriptors as existed on 1376 * the other node 1377 */ 1378 1379 retry_open: 1380 failover_open = 0; 1381 open_failed = 0; 1382 if (cd >= 0) { 1383 failover_open++; 1384 cdi = &(_sd_cache_files[cd]); 1385 mutex_enter(&_sd_cache_lock); 1386 if (cdi->cd_info == NULL) 1387 cdi->cd_info = &_sd_cache_stats->st_shared[cd]; 1388 else if (cdi->cd_info->sh_alloc && 1389 strcmp(cdi->cd_info->sh_filename, filename)) { 1390 cmn_err(CE_WARN, "!sdbc(_sd_open_cd) cd %d mismatch", 1391 cd); 1392 mutex_exit(&_sd_cache_lock); 1393 return (-EEXIST); 1394 } 1395 1396 if (cdi->cd_info->sh_failed != 2) { 1397 if (cdi->cd_info->sh_alloc != 0) 1398 preexists = 1; 1399 else { 1400 cdi->cd_info->sh_alloc = CD_ALLOC_IN_PROGRESS; 1401 (void) strcpy(cdi->cd_info->sh_filename, 1402 filename); 1403 if (_sd_cache_stats->st_count < sdbc_max_devs) 1404 _sd_cache_stats->st_count++; 1405 } 1406 } 1407 1408 mutex_exit(&_sd_cache_lock); 1409 alloc_cd = cd; 1410 1411 goto known_cd; 1412 } 1413 1414 new_cd = 0; 1415 mutex_enter(&_sd_cache_lock); 1416 1417 for (cdi = &(_sd_cache_files[new_cd]), 1418 cdg = _sdbc_gl_file_info + new_cd; 1419 new_cd < (sdbc_max_devs); new_cd++, cdi++, cdg++) { 1420 if (strlen(cdg->sv_volname) != 0) 1421 if (strcmp(cdg->sv_volname, filename)) 1422 continue; 1423 1424 if (cdi->cd_info == NULL) 1425 cdi->cd_info = &_sd_cache_stats->st_shared[new_cd]; 1426 1427 if (cdi->cd_info->sh_failed != 2) { 1428 if (cdi->cd_info->sh_alloc != 0) 1429 preexists = 1; 1430 else { 1431 if (cd == -2) { 1432 mutex_exit(&_sd_cache_lock); 1433 return (-1); 1434 } 1435 cdi->cd_info->sh_alloc = CD_ALLOC_IN_PROGRESS; 1436 (void) strcpy(cdi->cd_info->sh_filename, 1437 filename); 1438 (void) strcpy(cdg->sv_volname, filename); 1439 1440 cdg->sv_cd = new_cd; 1441 /* update safestore */ 1442 SSOP_SETVOL(sdbc_safestore, cdg); 1443 if (_sd_cache_stats->st_count < sdbc_max_devs) 1444 _sd_cache_stats->st_count++; 1445 cdi->cd_flag = 0; 1446 } 1447 } 1448 alloc_cd = new_cd; 1449 break; 1450 } 1451 1452 mutex_exit(&_sd_cache_lock); 1453 1454 if (alloc_cd == -1) 1455 return (-ENOSPC); 1456 1457 known_cd: 1458 /* 1459 * If preexists: someone else is attempting to open this file as 1460 * well. Do only one open, but block everyone else here till the 1461 * open is completed. 1462 */ 1463 if (preexists) { 1464 while (cdi->cd_info->sh_alloc == CD_ALLOC_IN_PROGRESS) { 1465 delay(drv_usectohz(20000)); 1466 } 1467 if ((cdi->cd_info->sh_alloc != CD_ALLOCATED)) 1468 goto retry_open; 1469 return (alloc_cd); 1470 } 1471 1472 if (!(cdi->cd_rawfd = 1473 nsc_open(filename, NSC_SDBC_ID|NSC_DEVICE, _sdbc_fd_def, 1474 (blind_t)(unsigned long)alloc_cd, &rc)) || 1475 !nsc_getval(cdi->cd_rawfd, "DevMaj", (int *)&devmaj) || 1476 !nsc_getval(cdi->cd_rawfd, "DevMin", (int *)&devmin)) { 1477 if (cdi->cd_rawfd) { 1478 (void) nsc_close(cdi->cd_rawfd); 1479 cdi->cd_rawfd = NULL; 1480 } 1481 /* 1482 * take into account that there may be pinned data on a 1483 * device that can no longer be opened 1484 */ 1485 open_failed++; 1486 if (!(cdi->cd_info->sh_failed) && !failover_open) { 1487 cdi->cd_info->sh_alloc = 0; 1488 mutex_enter(&_sd_cache_lock); 1489 _sd_cache_stats->st_count--; 1490 mutex_exit(&_sd_cache_lock); 1491 if (!rc) 1492 rc = EIO; 1493 return (-rc); 1494 } 1495 } 1496 1497 cdi->cd_strategy = nsc_get_strategy(devmaj); 1498 cdi->cd_crdev = makedevice(devmaj, devmin); 1499 cdi->cd_desc = alloc_cd; 1500 cdi->cd_dirty_head = cdi->cd_dirty_tail = NULL; 1501 cdi->cd_io_head = cdi->cd_io_tail = NULL; 1502 cdi->cd_hint = 0; 1503 #ifdef DEBUG 1504 /* put the dev_t in the ioerr_inject_table */ 1505 _sdbc_ioj_set_dev(alloc_cd, cdi->cd_crdev); 1506 #endif 1507 1508 cdi->cd_global = (_sdbc_gl_file_info + alloc_cd); 1509 if (open_failed) { 1510 cdi->cd_info->sh_failed = 2; 1511 } else if (cdi->cd_info->sh_failed != 2) 1512 if ((cdi->cd_global->sv_pinned == _SD_SELF_HOST) && 1513 !failover_open) 1514 cdi->cd_info->sh_failed = 1; 1515 else 1516 cdi->cd_info->sh_failed = 0; 1517 1518 cdi->cd_flag |= flag; 1519 mutex_init(&cdi->cd_lock, NULL, MUTEX_DRIVER, NULL); 1520 1521 #ifndef _SD_NOTRACE 1522 (void) _sdbc_tr_configure(alloc_cd); 1523 #endif 1524 cdi->cd_info->sh_alloc = CD_ALLOCATED; 1525 cdi->cd_global = (_sdbc_gl_file_info + alloc_cd); 1526 cdi->cd_info->sh_cd = (unsigned short) alloc_cd; 1527 mutex_enter(&_sd_cache_lock); 1528 _sd_cache_stats->st_loc_count++; 1529 mutex_exit(&_sd_cache_lock); 1530 1531 if (cd_kstat_add(alloc_cd) < 0) { 1532 cmn_err(CE_WARN, "!Could not create kstats for cache descriptor" 1533 " %d", alloc_cd); 1534 } 1535 1536 1537 return (open_failed ? -EIO : alloc_cd); 1538 } 1539 1540 1541 /* 1542 * _sd_close - Close a cache descriptor. 1543 * 1544 * ARGUMENTS: 1545 * cd - the cache descriptor to be closed. 1546 * RETURNS: 1547 * 0 on success. 1548 * Error otherwise. 1549 * 1550 * Note: Under Construction. 1551 */ 1552 1553 int 1554 _sd_close(int cd) 1555 { 1556 int rc; 1557 _sd_cd_info_t *cdi = &(_sd_cache_files[cd]); 1558 1559 if (!FILE_OPENED(cd)) { 1560 rc = EINVAL; 1561 goto out; 1562 } 1563 1564 SDTRACE(ST_ENTER|SDF_CLOSE, cd, 0, SDT_INV_BL, 0, 0); 1565 1566 mutex_enter(&_sd_cache_lock); 1567 if ((cdi->cd_info->sh_alloc == 0) || 1568 (cdi->cd_info->sh_alloc & CD_CLOSE_IN_PROGRESS)) { 1569 mutex_exit(&_sd_cache_lock); 1570 SDTRACE(ST_EXIT|SDF_CLOSE, cd, 0, SDT_INV_BL, 0, EINVAL); 1571 rc = EINVAL; 1572 goto out; 1573 } 1574 cdi->cd_info->sh_alloc |= CD_CLOSE_IN_PROGRESS; 1575 mutex_exit(&_sd_cache_lock); 1576 1577 /* 1578 * _sd_flush_cd() will return -1 for the case where pinned 1579 * data is present, but has been transfered to the mirror 1580 * node. In this case it is safe to close the device as 1581 * though _sd_flush_cd() had returned 0. 1582 */ 1583 1584 rc = _sd_flush_cd(cd); 1585 if (rc == -1) 1586 rc = 0; 1587 1588 if (rc != 0) { 1589 mutex_enter(&_sd_cache_lock); 1590 if ((rc == EAGAIN) && 1591 (cdi->cd_global->sv_pinned == _SD_NO_HOST)) { 1592 cdi->cd_global->sv_pinned = _SD_SELF_HOST; 1593 SSOP_SETVOL(sdbc_safestore, cdi->cd_global); 1594 } 1595 1596 cdi->cd_info->sh_alloc &= ~CD_CLOSE_IN_PROGRESS; 1597 mutex_exit(&_sd_cache_lock); 1598 SDTRACE(ST_EXIT|SDF_CLOSE, cd, 0, SDT_INV_BL, 1599 _SD_CD_WBLK_USED(cd), rc); 1600 goto out; 1601 } 1602 1603 rc = nsc_close(cdi->cd_rawfd); 1604 if (rc) { 1605 mutex_enter(&_sd_cache_lock); 1606 cdi->cd_info->sh_alloc &= ~CD_CLOSE_IN_PROGRESS; 1607 mutex_exit(&_sd_cache_lock); 1608 SDTRACE(ST_EXIT|SDF_CLOSE, cd, 0, SDT_INV_BL, 0, rc); 1609 goto out; 1610 } 1611 mutex_enter(&_sd_cache_lock); 1612 _sd_cache_stats->st_loc_count--; 1613 mutex_exit(&_sd_cache_lock); 1614 1615 if (cd_kstat_remove(cd) < 0) { 1616 cmn_err(CE_WARN, "!Could not remove kstat for cache descriptor " 1617 "%d", cd); 1618 } 1619 1620 cdi->cd_info->sh_alloc = 0; 1621 cdi->cd_info->sh_failed = 0; 1622 /* cdi->cd_info = NULL; */ 1623 cdi->cd_flag = 0; 1624 SDTRACE(ST_EXIT|SDF_CLOSE, cd, 0, SDT_INV_BL, 0, NSC_DONE); 1625 rc = NSC_DONE; 1626 goto out; 1627 1628 out: 1629 return (rc); 1630 } 1631 1632 1633 static int 1634 _sd_close_io(blind_t xcd) 1635 { 1636 _sd_cd_info_t *cdi; 1637 int cd = (int)(unsigned long)xcd; 1638 int rc = 0; 1639 1640 if ((rc = _sd_close((int)cd)) == NSC_DONE) { 1641 cdi = &(_sd_cache_files[cd]); 1642 cdi->cd_iodev = NULL; 1643 } 1644 1645 return (rc); 1646 } 1647 1648 1649 /* 1650 * _sdbc_remote_store_pinned - reflect pinned/failed blocks for cd 1651 * to our remote mirror. Returns count of blocks reflected or -1 on error. 1652 * 1653 */ 1654 int 1655 _sdbc_remote_store_pinned(int cd) 1656 { 1657 int cnt = 0; 1658 _sd_cd_info_t *cdi = &(_sd_cache_files[cd]); 1659 _sd_cctl_t *cc_ent, *cc_list; 1660 1661 ASSERT(cd >= 0); 1662 if (cdi->cd_info->sh_failed) { 1663 1664 if (cdi->cd_global->sv_pinned == _SD_NO_HOST) { 1665 cdi->cd_global->sv_pinned = _SD_SELF_HOST; 1666 SSOP_SETVOL(sdbc_safestore, cdi->cd_global); 1667 } 1668 1669 mutex_enter(&cdi->cd_lock); 1670 cc_ent = cc_list = cdi->cd_fail_head; 1671 while (cc_ent) { 1672 cnt++; 1673 1674 /* is this always necessary? jgk */ 1675 1676 if (SSOP_WRITE_CBLOCK(sdbc_safestore, 1677 cc_ent->cc_write->sc_res, cc_ent->cc_data, 1678 CACHE_BLOCK_SIZE, 0)) { 1679 mutex_exit(&cdi->cd_lock); 1680 return (-1); 1681 } 1682 1683 /* update the cache block metadata */ 1684 CENTRY_SET_FTPOS(cc_ent); 1685 cc_ent->cc_write->sc_flag = cc_ent->cc_flag; 1686 1687 cc_ent->cc_write->sc_dirty = CENTRY_DIRTY(cc_ent); 1688 1689 SSOP_SETCENTRY(sdbc_safestore, cc_ent->cc_write); 1690 1691 cc_ent = cc_ent->cc_dirty_next; 1692 if (!cc_ent) 1693 cc_ent = cc_list = cc_list->cc_dirty_link; 1694 } 1695 mutex_exit(&cdi->cd_lock); 1696 } 1697 1698 return (cnt); 1699 } 1700 1701 /* 1702 * _sd_flush_cd() 1703 * reflect pinned blocks to mirrored node 1704 * wait for dirty blocks to be flushed 1705 * returns: 1706 * EIO I/O failure, or pinned blocks and no mirror 1707 * EAGAIN Hang: count of outstanding writes isn't decreasing 1708 * -1 pinned blocks, reflected to mirror 1709 * 0 success 1710 */ 1711 static int 1712 _sd_flush_cd(int cd) 1713 { 1714 int rc; 1715 1716 if ((rc = _sd_wait_for_flush(cd)) == 0) 1717 return (0); 1718 1719 /* 1720 * if we timed out simply return otherwise 1721 * it must be an i/o type of error 1722 */ 1723 if (rc == EAGAIN) 1724 return (rc); 1725 1726 if (_sd_is_mirror_down()) 1727 return (EIO); /* already failed, no mirror */ 1728 1729 /* flush any pinned/failed blocks to mirror */ 1730 if (_sdbc_remote_store_pinned(cd) >= 0) 1731 /* 1732 * At this point it looks like we have blocks on the 1733 * failed list and taking up space on this node but 1734 * no longer have responsibility for the blocks. 1735 * These blocks will in fact be freed from the cache 1736 * and the failed list when the mirror picks them up 1737 * from safe storage and then calls _sd_cd_discard_mirror 1738 * which will issue an rpc telling us to finish up. 1739 * 1740 * Should the other node die before sending the rpc then 1741 * we are safe with these blocks simply waiting on the 1742 * failed list. 1743 */ 1744 return (-1); 1745 else 1746 return (rc); 1747 } 1748 1749 /* 1750 * _sdbc_io_attach_cd -- set up for client access to device, reserve raw device 1751 * 1752 * ARGUMENTS: 1753 * cd - the cache descriptor to attach. 1754 * 1755 * RETURNS: 1756 * 0 on success. 1757 * Error otherwise. 1758 */ 1759 int 1760 _sdbc_io_attach_cd(blind_t xcd) 1761 { 1762 int rc = 0; 1763 _sd_cd_info_t *cdi; 1764 int cd = (int)(unsigned long)xcd; 1765 1766 SDTRACE(ST_ENTER|SDF_ATTACH, cd, 0, SDT_INV_BL, 0, 0); 1767 if (!_sd_cache_initialized || 1768 _sdbc_shutdown_in_progress || 1769 !FILE_OPENED(cd)) { 1770 SDTRACE(ST_EXIT|SDF_ATTACH, cd, 0, SDT_INV_BL, 0, EINVAL); 1771 1772 DTRACE_PROBE(_sdbc_io_attach_cd_end1); 1773 1774 return (EINVAL); 1775 } 1776 cdi = &(_sd_cache_files[cd]); 1777 1778 /* 1779 * check if disk is failed without raw device open. If it is, 1780 * it has to be recovered using _sd_disk_online 1781 */ 1782 1783 if (cdi->cd_global->sv_pinned == _SD_SELF_HOST) { 1784 _sd_print(3, 1785 "_sdbc_io_attach_cd: pinned data. returning EINVAL"); 1786 1787 DTRACE_PROBE(_sdbc_io_attach_cd_end2); 1788 1789 return (EINVAL); 1790 } 1791 1792 if ((cdi->cd_info == NULL) || (cdi->cd_info->sh_failed)) { 1793 DTRACE_PROBE1(_sdbc_io_attach_cd_end3, 1794 struct _sd_shared *, cdi->cd_info); 1795 1796 return (EINVAL); 1797 } 1798 1799 #if defined(_SD_FAULT_RES) 1800 /* wait for node recovery to finish */ 1801 if (_sd_node_recovery) 1802 (void) _sd_recovery_wait(); 1803 #endif 1804 1805 /* this will provoke a sdbc_fd_attach_cd call .. */ 1806 1807 rc = nsc_reserve(cdi->cd_rawfd, NSC_MULTI); 1808 SDTRACE(ST_EXIT|SDF_ATTACH, cd, 0, SDT_INV_BL, 0, rc); 1809 1810 return (rc); 1811 } 1812 1813 /* 1814 * sdbc_fd_attach_cd -- setup cache for access to raw device underlying cd. 1815 * This is provoked by some piece of sdbc doing a reserve on the raw device. 1816 * 1817 * ARGUMENTS: 1818 * cd - the cache descriptor to attach. 1819 * 1820 * RETURNS: 1821 * 0 on success. 1822 * Error otherwise. 1823 */ 1824 static int 1825 sdbc_fd_attach_cd(blind_t xcd) 1826 { 1827 int rc = 0; 1828 int cd = (int)(unsigned long)xcd; 1829 _sd_cd_info_t *cdi; 1830 1831 if (!_sd_cache_initialized || !FILE_OPENED(cd)) { 1832 SDTRACE(ST_INFO|SDF_ATTACH, cd, 0, SDT_INV_BL, 0, EINVAL); 1833 1834 DTRACE_PROBE(sdbc_fd_attach_cd_end1); 1835 1836 return (EINVAL); 1837 } 1838 cdi = &(_sd_cache_files[cd]); 1839 1840 #if defined(_SD_FAULT_RES) 1841 /* retrieve pinned/failed data */ 1842 if (!_sd_node_recovery) { 1843 (void) _sd_repin_cd(cd); 1844 } 1845 #endif 1846 1847 rc = nsc_partsize(cdi->cd_rawfd, &cdi->cd_info->sh_filesize); 1848 if (rc != 0) { 1849 SDTRACE(ST_INFO|SDF_ATTACH, cd, 0, SDT_INV_BL, 0, rc); 1850 1851 DTRACE_PROBE(sdbc_fd_attach_cd_end3); 1852 1853 return (rc); 1854 } 1855 1856 cdi->cd_global->sv_attached = _SD_SELF_HOST; 1857 1858 SSOP_SETVOL(sdbc_safestore, cdi->cd_global); 1859 1860 mutex_enter(&_sd_cache_lock); 1861 cdi->cd_info->sh_flag |= CD_ATTACHED; 1862 mutex_exit(&_sd_cache_lock); 1863 1864 return (0); 1865 } 1866 1867 /* 1868 * _sdbc_io_detach_cd -- release raw device 1869 * Called when a cache client is being detached from this cd. 1870 * 1871 * ARGUMENTS: 1872 * cd - the cache descriptor to detach. 1873 * RETURNS: 1874 * 0 on success. 1875 * Error otherwise. 1876 */ 1877 int 1878 _sdbc_io_detach_cd(blind_t xcd) 1879 { 1880 int cd = (int)(unsigned long)xcd; 1881 _sd_cd_info_t *cdi; 1882 1883 1884 SDTRACE(ST_ENTER|SDF_DETACH, cd, 0, SDT_INV_BL, 0, 0); 1885 if (!_sd_cache_initialized || !FILE_OPENED(cd)) { 1886 SDTRACE(ST_EXIT|SDF_DETACH, cd, 0, SDT_INV_BL, 0, EINVAL); 1887 1888 DTRACE_PROBE(_sdbc_io_detach_cd_end1); 1889 1890 return (EINVAL); 1891 } 1892 1893 #if defined(_SD_FAULT_RES) 1894 if (_sd_node_recovery) 1895 (void) _sd_recovery_wait(); 1896 #endif 1897 /* relinquish responsibility for device */ 1898 cdi = &(_sd_cache_files[cd]); 1899 if (!(cdi->cd_rawfd) || !nsc_held(cdi->cd_rawfd)) { 1900 cmn_err(CE_WARN, "!sdbc(_sdbc_detach_cd)(%d) not attached", cd); 1901 SDTRACE(ST_EXIT|SDF_DETACH, cd, 0, SDT_INV_BL, 0, EPROTO); 1902 DTRACE_PROBE1(_sdbc_io_detach_cd_end2, 1903 nsc_fd_t *, cdi->cd_rawfd); 1904 1905 return (EPROTO); 1906 } 1907 /* this will provoke/allow a call to sdbc_fd_detach_cd */ 1908 nsc_release(cdi->cd_rawfd); 1909 1910 SDTRACE(ST_EXIT|SDF_DETACH, cd, 0, SDT_INV_BL, 0, 0); 1911 1912 return (0); 1913 } 1914 1915 /* 1916 * _sdbc_detach_cd -- flush dirty writes to disk, release raw device 1917 * Called when raw device is being detached from this cd. 1918 * 1919 * ARGUMENTS: 1920 * cd - the cache descriptor to detach. 1921 * rd_only - non-zero if detach is for read access. 1922 * RETURNS: 1923 * 0 on success. 1924 * Error otherwise. 1925 */ 1926 static int 1927 sdbc_detach_cd(blind_t xcd, int rd_only) 1928 { 1929 int rc; 1930 int cd = (int)(unsigned long)xcd; 1931 _sd_cd_info_t *cdi; 1932 1933 SDTRACE(ST_INFO|SDF_DETACH, cd, 0, SDT_INV_BL, 0, 0); 1934 1935 if (!_sd_cache_initialized || !FILE_OPENED(cd)) { 1936 SDTRACE(ST_INFO|SDF_DETACH, cd, 0, SDT_INV_BL, 0, EINVAL); 1937 1938 DTRACE_PROBE(sdbc_detach_cd_end1); 1939 1940 return (EINVAL); 1941 } 1942 1943 1944 rc = _sd_flush_cd(cd); 1945 if (rc > 0) { 1946 SDTRACE(ST_INFO|SDF_DETACH, cd, 0, SDT_INV_BL, 0, rc); 1947 1948 DTRACE_PROBE(sdbc_detach_cd_end2); 1949 1950 return (rc); 1951 } 1952 1953 if (!rd_only) { 1954 _sd_hash_invalidate_cd(cd); 1955 cdi = &(_sd_cache_files[cd]); 1956 1957 if (cdi->cd_global->sv_attached == _SD_SELF_HOST) { 1958 cdi->cd_global->sv_attached = _SD_NO_HOST; 1959 SSOP_SETVOL(sdbc_safestore, cdi->cd_global); 1960 } else { 1961 cmn_err(CE_WARN, 1962 "!sdbc(_sdbc_detach_cd) (%d) attached by node %d", 1963 cd, cdi->cd_global->sv_attached); 1964 SDTRACE(SDF_DETACH, cd, 0, SDT_INV_BL, 0, EPROTO); 1965 1966 DTRACE_PROBE1(sdbc_detach_cd_end3, 1967 int, cdi->cd_global->sv_attached); 1968 1969 return (EPROTO); 1970 } 1971 1972 mutex_enter(&_sd_cache_lock); 1973 cdi->cd_info->sh_flag &= ~CD_ATTACHED; 1974 mutex_exit(&_sd_cache_lock); 1975 } 1976 1977 SDTRACE(ST_INFO|SDF_DETACH, cd, 0, SDT_INV_BL, 0, 0); 1978 1979 return (0); 1980 } 1981 1982 /* 1983 * _sdbc_fd_detach_cd -- flush dirty writes to disk, release raw device 1984 * Called when raw device is being detached from this cd. 1985 * 1986 * ARGUMENTS: 1987 * xcd - the cache descriptor to detach. 1988 * RETURNS: 1989 * 0 on success. 1990 * Error otherwise. 1991 */ 1992 static int 1993 sdbc_fd_detach_cd(blind_t xcd) 1994 { 1995 return (sdbc_detach_cd(xcd, 0)); 1996 } 1997 1998 /* 1999 * sdbc_fd_flush_cd - raw device "xcd" is being detached and needs 2000 * flushing. We only need to flush we don't need to hash invalidate 2001 * this file. 2002 */ 2003 static int 2004 sdbc_fd_flush_cd(blind_t xcd) 2005 { 2006 return (sdbc_detach_cd(xcd, 1)); 2007 } 2008 2009 /* 2010 * _sd_get_pinned - re-issue PINNED callbacks for cache device 2011 * 2012 * ARGUMENTS: 2013 * cd - the cache descriptor to reissue pinned calbacks from. 2014 * RETURNS: 2015 * 0 on success. 2016 * Error otherwise. 2017 */ 2018 int 2019 _sd_get_pinned(blind_t xcd) 2020 { 2021 _sd_cd_info_t *cdi; 2022 _sd_cctl_t *cc_list, *cc_ent; 2023 int cd = (int)(unsigned long)xcd; 2024 2025 cdi = &_sd_cache_files[cd]; 2026 2027 if (cd < 0 || cd >= sdbc_max_devs) { 2028 DTRACE_PROBE(_sd_get_pinned_end1); 2029 return (EINVAL); 2030 } 2031 2032 if (!FILE_OPENED(cd)) { 2033 DTRACE_PROBE(_sd_get_pinned_end2); 2034 return (0); 2035 } 2036 2037 mutex_enter(&cdi->cd_lock); 2038 2039 if (!cdi->cd_info->sh_failed) { 2040 mutex_exit(&cdi->cd_lock); 2041 2042 DTRACE_PROBE(_sd_get_pinned_end3); 2043 return (0); 2044 } 2045 2046 cc_ent = cc_list = cdi->cd_fail_head; 2047 while (cc_ent) { 2048 if (CENTRY_PINNED(cc_ent)) 2049 nsc_pinned_data(cdi->cd_iodev, 2050 BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)), BLK_FBAS); 2051 cc_ent = cc_ent->cc_dirty_next; 2052 if (!cc_ent) 2053 cc_ent = cc_list = cc_list->cc_dirty_link; 2054 } 2055 2056 mutex_exit(&cdi->cd_lock); 2057 2058 return (0); 2059 } 2060 2061 /* 2062 * _sd_allocate_buf - allocate a vector of buffers for io. 2063 * *This call has been replaced by _sd_alloc_buf* 2064 */ 2065 2066 _sd_buf_handle_t * 2067 _sd_allocate_buf(int cd, nsc_off_t fba_pos, nsc_size_t fba_len, int flag, 2068 int *sts) 2069 { 2070 _sd_buf_handle_t *handle = NULL; 2071 2072 *sts = _sd_alloc_buf((blind_t)(unsigned long)cd, fba_pos, fba_len, 2073 flag, &handle); 2074 if (*sts == NSC_HIT) 2075 *sts = NSC_DONE; 2076 return (handle); 2077 } 2078 2079 2080 /* 2081 * _sd_prefetch_buf - _sd_alloc_buf w/flag = NSC_RDAHEAD|NSC_RDBUF 2082 * no 'bufvec' (data is not read by caller) 2083 * skip leading valid or busy entries (data available sooner) 2084 * truncate on busy block (to avoid deadlock) 2085 * release trailing valid entries, adjust length before starting I/O. 2086 */ 2087 static int 2088 _sd_prefetch_buf(int cd, nsc_off_t fba_pos, nsc_size_t fba_len, int flag, 2089 _sd_buf_handle_t *handle, int locked) 2090 { 2091 _sd_cd_info_t *cdi; 2092 nsc_off_t cblk; /* position of temp cache block */ 2093 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 2094 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 2095 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 2096 nsc_off_t io_pos; /* offset in FBA's */ 2097 nsc_size_t fba_orig_len; 2098 int sts, stall; 2099 _sd_cctl_t *centry = NULL; 2100 _sd_cctl_t *lentry = NULL; 2101 _sd_cctl_t *ioent = NULL; 2102 _sd_cctl_t *last_ioent = NULL; 2103 sdbc_allocbuf_t alloc_tok = {0}; 2104 int this_entry_type = 0; 2105 nsc_size_t request_blocks = 0; /* number of cache blocks required */ 2106 int pageio; 2107 2108 handle->bh_flag |= NSC_HACTIVE; 2109 ASSERT(cd >= 0); 2110 cdi = &_sd_cache_files[cd]; 2111 2112 /* prefetch: truncate if req'd */ 2113 if (fba_len > sdbc_max_fbas) 2114 fba_len = sdbc_max_fbas; 2115 if ((fba_pos + fba_len) > cdi->cd_info->sh_filesize) { 2116 if (fba_pos >= cdi->cd_info->sh_filesize) { 2117 sts = EIO; 2118 goto done; 2119 } 2120 fba_len = cdi->cd_info->sh_filesize - fba_pos; 2121 } 2122 2123 fba_orig_len = fba_len; 2124 2125 _SD_SETUP_HANDLE(handle, cd, fba_pos, fba_len, flag); 2126 handle->bh_centry = NULL; 2127 2128 cblk = FBA_TO_BLK_NUM(fba_pos); 2129 st_cblk_off = BLK_FBA_OFF(fba_pos); 2130 st_cblk_len = BLK_FBAS - st_cblk_off; 2131 2132 /* 2133 * count number of blocks on chain that is required 2134 */ 2135 if ((nsc_size_t)st_cblk_len >= fba_len) { 2136 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 2137 end_cblk_len = 0; 2138 } else { 2139 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 2140 } 2141 2142 request_blocks = 1; /* at least one */ 2143 2144 /* middle piece */ 2145 request_blocks += (fba_len - (st_cblk_len + end_cblk_len)) >> 2146 BLK_FBA_SHFT; 2147 2148 if (end_cblk_len) 2149 ++request_blocks; 2150 2151 stall = 0; 2152 do { 2153 pageio = ((flag & NSC_PAGEIO) != 0 || sdbc_pageio_always != 0); 2154 cget: 2155 if (centry = (_sd_cctl_t *) 2156 _sd_hash_search(cd, cblk, _sd_htable)) { 2157 try: 2158 /* prefetch: skip leading valid blocks */ 2159 if ((ioent == NULL) && 2160 SDBC_VALID_BITS(st_cblk_off, st_cblk_len, centry)) { 2161 skip: 2162 sdbc_prefetch_valid_cnt++; 2163 --request_blocks; 2164 lentry = centry; 2165 centry = NULL; 2166 cblk++; 2167 fba_len -= st_cblk_len; 2168 st_cblk_off = 0; 2169 st_cblk_len = (sdbc_cblk_fba_t) 2170 ((fba_len > (nsc_size_t)BLK_FBAS) ? 2171 BLK_FBAS : fba_len); 2172 continue; 2173 } 2174 2175 if (SET_CENTRY_INUSE(centry)) { 2176 /* 2177 * prefetch: skip leading busy 2178 * or truncate at busy block 2179 */ 2180 if (ioent == NULL) 2181 goto skip; 2182 sdbc_prefetch_busy_cnt++; 2183 fba_orig_len -= fba_len; 2184 fba_len = 0; 2185 centry = lentry; /* backup */ 2186 break; 2187 } 2188 2189 /* 2190 * bug 4529671 2191 * now that we own the centry make sure that 2192 * it is still good. it could have been processed 2193 * by _sd_dealloc_dm() in the window between 2194 * _sd_hash_search() and SET_CENTRY_INUSE(). 2195 */ 2196 if ((_sd_cctl_t *) 2197 _sd_hash_search(cd, cblk, _sd_htable) != centry) { 2198 sdbc_prefetch_deallocd++; 2199 #ifdef DEBUG 2200 cmn_err(CE_WARN, 2201 "!prefetch centry %p cd %d cblk %" NSC_SZFMT 2202 " fba_len %" NSC_SZFMT " lost to dealloc?! " 2203 "cc_data %p", 2204 (void *)centry, cd, cblk, fba_orig_len, 2205 (void *)centry->cc_data); 2206 #endif 2207 2208 CLEAR_CENTRY_INUSE(centry); 2209 continue; 2210 } 2211 2212 if (CC_CD_BLK_MATCH(cd, cblk, centry)) { 2213 /* 2214 * Do pagelist io mutual exclusion 2215 * before messing with the centry. 2216 */ 2217 if (pageio && SET_CENTRY_PAGEIO(centry)) { 2218 /* flusher not done with pageio */ 2219 /* 2220 * prefetch: skip leading busy 2221 * or truncate at busy block 2222 */ 2223 CLEAR_CENTRY_INUSE(centry); 2224 if (ioent == NULL) 2225 goto skip; 2226 sdbc_prefetch_pageio1++; 2227 fba_orig_len -= fba_len; 2228 fba_len = 0; 2229 centry = lentry; /* backup */ 2230 break; 2231 2232 } 2233 2234 sdbc_prefetch_hit++; 2235 this_entry_type = HASH_ENTRY_DM; 2236 pageio = 0; 2237 centry->cc_toflush = 0; 2238 2239 centry->cc_hits++; 2240 2241 /* this will reset the age flag */ 2242 sdbc_centry_init_dm(centry); 2243 2244 DTRACE_PROBE1(_sd_prefetch_buf, 2245 _sd_cctl_t *, centry); 2246 } else { 2247 /* block mismatch */ 2248 sdbc_prefetch_lost++; 2249 2250 CLEAR_CENTRY_INUSE(centry); 2251 continue; 2252 } 2253 } else { 2254 centry = sdbc_centry_alloc(cd, cblk, request_blocks, 2255 &stall, &alloc_tok, ALLOC_NOWAIT); 2256 2257 if (centry == NULL) { 2258 /* 2259 * prefetch: cache is very busy. just do 2260 * the i/o for the blocks already acquired, 2261 * if any. 2262 */ 2263 fba_orig_len -= fba_len; 2264 fba_len = 0; 2265 /* 2266 * if we have a chain of centry's 2267 * then back up (set centry to lentry). 2268 * if there is no chain (ioent == NULL) 2269 * then centry remains NULL. this can occur 2270 * if all previous centrys were hash hits 2271 * on valid blocks that were processed in 2272 * the skip logic above. 2273 */ 2274 if (ioent) 2275 centry = lentry; /* backup */ 2276 break; 2277 } 2278 2279 /* 2280 * dmchaining adjustment. 2281 * if centry was obtained from the dmchain 2282 * then clear local pageio variable because the 2283 * centry already has cc_pageio set. 2284 */ 2285 if (CENTRY_PAGEIO(centry)) 2286 pageio = 0; 2287 2288 DTRACE_PROBE1(_sd_alloc_buf, _sd_cctl_t *, centry); 2289 2290 this_entry_type = ELIGIBLE_ENTRY_DM; 2291 if (centry->cc_aging_dm & FOUND_IN_HASH_DM) 2292 this_entry_type = HASH_ENTRY_DM; 2293 else { 2294 if (centry->cc_aging_dm & FOUND_HOLD_OVER_DM) 2295 this_entry_type = HOLD_ENTRY_DM; 2296 } 2297 } 2298 2299 centry->cc_chain = NULL; 2300 2301 centry->cc_aging_dm &= ~(FOUND_IN_HASH_DM|FOUND_HOLD_OVER_DM); 2302 2303 /* 2304 * Do pagelist io mutual exclusion now if we did not do 2305 * it above. 2306 */ 2307 2308 if (pageio && SET_CENTRY_PAGEIO(centry)) { 2309 /* flusher not done with pageio */ 2310 sdbc_prefetch_pageio2++; 2311 2312 /* 2313 * prefetch: skip leading busy 2314 * or truncate at busy block 2315 */ 2316 CLEAR_CENTRY_INUSE(centry); 2317 if (ioent == NULL) 2318 goto skip; 2319 sdbc_prefetch_busy_cnt++; 2320 fba_orig_len -= fba_len; 2321 fba_len = 0; 2322 centry = lentry; /* backup */ 2323 break; 2324 } 2325 2326 pageio = 0; 2327 2328 fba_len -= st_cblk_len; 2329 2330 if (ioent == NULL) { 2331 if (!SDBC_VALID_BITS(st_cblk_off, st_cblk_len, 2332 centry)) { 2333 io_pos = BLK_TO_FBA_NUM(cblk) + st_cblk_off; 2334 ioent = last_ioent = centry; 2335 } else { 2336 DATA_LOG(SDF_ALLOC, centry, st_cblk_off, 2337 st_cblk_len); 2338 DTRACE_PROBE4(_sd_prefetch_buf_data1, 2339 uint64_t, (uint64_t)(BLK_TO_FBA_NUM(cblk) + 2340 st_cblk_off), int, st_cblk_len, 2341 char *, *(int64_t *)(centry->cc_data + 2342 FBA_SIZE(st_cblk_off)), char *, 2343 *(int64_t *)(centry->cc_data + 2344 FBA_SIZE(st_cblk_off + st_cblk_len) - 8)); 2345 } 2346 2347 handle->bh_centry = centry; 2348 st_cblk_off = 0; 2349 st_cblk_len = (sdbc_cblk_fba_t) 2350 ((fba_len > (nsc_size_t)BLK_FBAS) ? 2351 BLK_FBAS : fba_len); 2352 } else { 2353 if (!SDBC_VALID_BITS(st_cblk_off, st_cblk_len, centry)) 2354 last_ioent = centry; 2355 else { 2356 DTRACE_PROBE4(_sd_prefetch_buf_data2, 2357 uint64_t, (uint64_t)(BLK_TO_FBA_NUM(cblk) + 2358 st_cblk_off), int, st_cblk_len, 2359 char *, *(int64_t *)(centry->cc_data + 2360 FBA_SIZE(st_cblk_off)), char *, 2361 *(int64_t *)(centry->cc_data + 2362 FBA_SIZE(st_cblk_off + st_cblk_len) - 8)); 2363 } 2364 2365 lentry->cc_chain = centry; 2366 if (fba_len < (nsc_size_t)BLK_FBAS) 2367 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 2368 } 2369 lentry = centry; 2370 cblk++; 2371 2372 /* if this block has a new identity clear prefetch history */ 2373 if (this_entry_type != HASH_ENTRY_DM) 2374 centry->cc_aging_dm &= 2375 ~(PREFETCH_BUF_I | PREFETCH_BUF_E); 2376 2377 centry->cc_aging_dm &= ~(ENTRY_FIELD_DM); 2378 centry->cc_aging_dm |= this_entry_type | PREFETCH_BUF_E; 2379 if (flag & NSC_METADATA) 2380 centry->cc_aging_dm |= STICKY_METADATA_DM; 2381 2382 --request_blocks; 2383 } while (fba_len > 0); 2384 2385 2386 if (locked) { 2387 rw_exit(&sdbc_queue_lock); 2388 locked = 0; 2389 } 2390 2391 sdbc_centry_alloc_end(&alloc_tok); 2392 2393 if (centry) { 2394 centry->cc_chain = NULL; 2395 if (sts = _sd_setup_category_on_type(handle->bh_centry)) { 2396 (void) _sd_free_buf(handle); 2397 goto done; 2398 } 2399 2400 (void) _sd_setup_mem_chaining(handle->bh_centry, 0); 2401 } 2402 2403 2404 if (ioent) { 2405 /* prefetch: trailing valid can be released, adjust len */ 2406 if ((centry != last_ioent)) { 2407 centry = last_ioent->cc_chain; 2408 last_ioent->cc_chain = NULL; 2409 while (centry) { 2410 lentry = centry->cc_chain; 2411 centry->cc_aging_dm &= ~PREFETCH_BUF_E; 2412 _sd_centry_release(centry); 2413 centry = lentry; 2414 sdbc_prefetch_trailing++; 2415 } 2416 fba_len = (CENTRY_BLK(last_ioent) - 2417 CENTRY_BLK(ioent) + 1) * BLK_FBAS - 2418 BLK_FBA_OFF(io_pos); 2419 fba_orig_len = fba_len + (io_pos - fba_pos); 2420 } 2421 2422 _SD_DISCONNECT_CALLBACK(handle); 2423 sts = _sd_doread(handle, ioent, io_pos, 2424 (fba_pos + fba_orig_len - io_pos), flag); 2425 if (sts > 0) 2426 (void) _sd_free_buf(handle); 2427 } else { 2428 CACHE_FBA_READ(cd, fba_orig_len); 2429 CACHE_READ_HIT; 2430 FBA_READ_IO_KSTATS(cd, FBA_SIZE(fba_orig_len)); 2431 2432 sts = NSC_HIT; 2433 } 2434 done: 2435 if (locked) 2436 rw_exit(&sdbc_queue_lock); 2437 2438 return (sts); 2439 } 2440 2441 2442 /* 2443 * _sd_cc_wait - wait for inuse cache block to become available 2444 * Usage: 2445 * if (SET_CENTRY_INUSE(centry)) { 2446 * _sd_cc_wait(cd, blk, centry, CC_INUSE); 2447 * goto try_again; 2448 * } 2449 * -or- 2450 * if (SET_CENTRY_PAGEIO(centry)) { 2451 * _sd_cc_wait(cd, blk, centry, CC_PAGEIO); 2452 * goto try_again; 2453 * } 2454 */ 2455 void 2456 _sd_cc_wait(int cd, nsc_off_t cblk, _sd_cctl_t *centry, int flag) 2457 { 2458 volatile ushort_t *waiters; 2459 volatile uchar_t *uflag; 2460 2461 if (flag == CC_INUSE) { 2462 waiters = &(centry->cc_await_use); 2463 uflag = &(CENTRY_INUSE(centry)); 2464 } else if (flag == CC_PAGEIO) { 2465 waiters = &(centry->cc_await_page); 2466 uflag = &(CENTRY_PAGEIO(centry)); 2467 } else { 2468 /* Oops! */ 2469 #ifdef DEBUG 2470 cmn_err(CE_WARN, "!_sd_cc_wait: unknown flag value (%x)", flag); 2471 #endif 2472 return; 2473 } 2474 2475 mutex_enter(¢ry->cc_lock); 2476 if (CC_CD_BLK_MATCH(cd, cblk, centry) && (*uflag) != 0) { 2477 (*waiters)++; 2478 sd_serialize(); 2479 if ((*uflag) != 0) { 2480 unsigned stime = nsc_usec(); 2481 cv_wait(¢ry->cc_blkcv, ¢ry->cc_lock); 2482 (*waiters)--; 2483 mutex_exit(¢ry->cc_lock); 2484 SDTRACE(ST_INFO|SDF_ENT_GET, 2485 cd, 0, BLK_TO_FBA_NUM(cblk), (nsc_usec()-stime), 0); 2486 } else { 2487 (*waiters)--; 2488 mutex_exit(¢ry->cc_lock); 2489 } 2490 } else 2491 mutex_exit(¢ry->cc_lock); 2492 2493 } 2494 2495 /* 2496 * _sd_alloc_buf - Allocate a vector of buffers for io. 2497 * 2498 * ARGUMENTS: 2499 * cd - Cache descriptor (from a previous open) 2500 * fba_pos - disk position (512-byte FBAs) 2501 * fba_len - length in disk FBAs. 2502 * flag - allocation type. Flag is one or more of 2503 * NSC_RDBUF, NSC_WRBUF, NSC_NOBLOCK and hints. 2504 * NSC_RDAHEAD - prefetch for future read. 2505 * handle_p - pointer to a handle pointer. 2506 * If the handle pointer is non-null, its used as a 2507 * pre-allocated handle. Else a new handle will be allocated 2508 * and stored in *handle_p 2509 * 2510 * RETURNS: 2511 * errno if return > 0. 2512 * else NSC_HIT or NSC_DONE on success 2513 * or NSC_PENDING on io in progress and NSC_NOBLOCK 2514 * specified in the flag. 2515 * USAGE: 2516 * This routine allocates the cache blocks requested and creates a list 2517 * of entries for this request. 2518 * If NSC_NOBLOCK was not specified, this call could block on read io. 2519 * If flag specified NSC_RDBUF and the request is not an entire 2520 * hit, an io is initiated. 2521 */ 2522 int 2523 _sd_alloc_buf(blind_t xcd, nsc_off_t fba_pos, nsc_size_t fba_len, int flag, 2524 _sd_buf_handle_t **handle_p) 2525 { 2526 int cd = (int)(unsigned long)xcd; 2527 _sd_cd_info_t *cdi; 2528 _sd_buf_handle_t *handle; 2529 int sts; 2530 nsc_off_t st_cblk, cblk; /* position of start and temp cache block */ 2531 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 2532 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 2533 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 2534 nsc_off_t io_pos; /* offset in FBA's */ 2535 _sd_bufvec_t *bufvec; 2536 _sd_cctl_t *centry, *lentry, *ioent = NULL; 2537 nsc_size_t fba_orig_len = fba_len; /* FBA length of orig request */ 2538 int stall, pageio; 2539 unsigned char cc_flag; 2540 int this_entry_type; 2541 int locked = 0; 2542 nsc_size_t dmchain_request_blocks; /* size of dmchain in cache blocks */ 2543 sdbc_allocbuf_t alloc_tok = {0}; 2544 int min_frag = 0; /* frag statistics */ 2545 int max_frag = 0; /* frag statistics */ 2546 int nfrags = 0; /* frag statistics */ 2547 #ifdef DEBUG 2548 int err = 0; 2549 #endif 2550 2551 2552 ASSERT(*handle_p != NULL); 2553 handle = *handle_p; 2554 2555 if (_sdbc_shutdown_in_progress) 2556 return (EIO); 2557 2558 if (xcd == NSC_ANON_CD) 2559 cd = _CD_NOHASH; 2560 2561 KSTAT_RUNQ_ENTER(cd); 2562 2563 /* 2564 * Force large writes on nvram systems to be write-through to 2565 * avoid the (slow) bcopy into nvram. 2566 */ 2567 2568 if (flag & NSC_WRBUF) { 2569 if (fba_len > (nsc_size_t)sdbc_wrthru_len) { 2570 flag |= NSC_WRTHRU; 2571 } 2572 } 2573 2574 #ifdef DEBUG 2575 if (sdbc_pageio_debug != SDBC_PAGEIO_OFF) { 2576 switch (sdbc_pageio_debug) { 2577 case SDBC_PAGEIO_RDEV: 2578 if (cd != _CD_NOHASH && 2579 sdbc_pageio_rdev != (dev_t)-1 && 2580 _sd_cache_files[cd].cd_crdev == sdbc_pageio_rdev) 2581 flag |= NSC_PAGEIO; 2582 break; 2583 2584 case SDBC_PAGEIO_RAND: 2585 if ((nsc_lbolt() % 3) == 0) 2586 flag |= NSC_PAGEIO; 2587 break; 2588 2589 case SDBC_PAGEIO_ALL: 2590 flag |= NSC_PAGEIO; 2591 break; 2592 } 2593 } 2594 #endif /* DEBUG */ 2595 2596 if (fba_len > (nsc_size_t)BLK_FBAS) { 2597 rw_enter(&sdbc_queue_lock, RW_WRITER); 2598 locked = 1; 2599 } 2600 2601 /* 2602 * _CD_NOHASH: client wants temporary (not hashed) cache memory 2603 * not associated with a local disk. Skip local disk checks. 2604 */ 2605 if (cd == _CD_NOHASH) { 2606 flag &= ~(NSC_RDBUF | NSC_WRBUF | NSC_RDAHEAD); 2607 handle = *handle_p; 2608 handle->bh_flag |= NSC_HACTIVE; 2609 goto setup; 2610 } 2611 2612 SDTRACE(ST_ENTER|SDF_ALLOCBUF, cd, fba_len, fba_pos, flag, 0); 2613 2614 2615 if ((flag & NSC_RDAHEAD) && _sd_prefetch_opt) { 2616 sts = _sd_prefetch_buf(cd, fba_pos, fba_len, flag, handle, 2617 locked); 2618 goto done; 2619 } 2620 2621 #if !defined(_SD_NOCHECKS) 2622 if (flag & NSC_RDAHEAD) { /* _sd_prefetch_opt == 0 */ 2623 nsc_size_t file_size; /* file_size in FBA's */ 2624 /* prefetch: truncate if req'd */ 2625 if (fba_len > sdbc_max_fbas) 2626 fba_len = sdbc_max_fbas; 2627 file_size = _sd_cache_files[(cd)].cd_info->sh_filesize; 2628 if ((fba_pos + fba_len) > file_size) { 2629 fba_len = file_size - fba_pos; 2630 #ifdef NSC_MULTI_TERABYTE 2631 if ((int64_t)fba_len <= 0) { 2632 #else 2633 if ((int32_t)fba_len <= 0) { 2634 #endif 2635 sts = EIO; 2636 SDTRACE(ST_EXIT|SDF_ALLOCBUF, cd, fba_len, 2637 fba_pos, flag, sts); 2638 goto done; 2639 } 2640 } 2641 } else 2642 if (sts = _sd_check_buffer_alloc(cd, fba_pos, fba_len, handle_p)) { 2643 SDTRACE(ST_EXIT|SDF_ALLOCBUF, cd, fba_len, fba_pos, flag, sts); 2644 goto done; 2645 } 2646 #endif 2647 if (fba_len == 0) { 2648 SDTRACE(ST_EXIT|SDF_ALLOCBUF, cd, fba_len, fba_pos, 2649 flag, EINVAL); 2650 sts = EINVAL; 2651 goto done; 2652 } 2653 2654 handle->bh_flag |= NSC_HACTIVE; 2655 cdi = &_sd_cache_files[cd]; 2656 2657 if (cdi->cd_recovering) { 2658 /* 2659 * If recovering this device, then block all allocates 2660 * for reading or writing. If we allow reads then 2661 * this path could see old data before we recover. 2662 * If we allow writes then new data could be overwritten 2663 * by old data. 2664 * This is clearly still not a complete solution as 2665 * the thread doing this allocate could conceivably be 2666 * by this point (and in _sd_write/_sd_read for that matter 2667 * which don't even have this protection). But this type 2668 * of path seems to only exist in a failover situation 2669 * where a device has failed on the other node and works 2670 * on this node so the problem is not a huge one but exists 2671 * never the less. 2672 */ 2673 if (sts = _sd_recovery_wblk_wait(cd)) { 2674 handle->bh_flag &= ~NSC_HACTIVE; 2675 SDTRACE(ST_EXIT|SDF_ALLOCBUF, cd, fba_len, fba_pos, 2676 flag, sts); 2677 goto done; 2678 } 2679 } 2680 2681 /* write & disk failed, return error immediately */ 2682 if ((flag & NSC_WRBUF) && cdi->cd_info->sh_failed) { 2683 handle->bh_flag &= ~NSC_HACTIVE; 2684 SDTRACE(ST_EXIT|SDF_ALLOCBUF, cd, fba_len, fba_pos, flag, EIO); 2685 sts = EIO; 2686 goto done; 2687 } 2688 2689 setup: 2690 2691 _SD_SETUP_HANDLE(handle, cd, fba_pos, fba_len, flag); 2692 handle->bh_centry = NULL; 2693 bufvec = handle->bh_bufvec; 2694 if (flag & NSC_RDAHEAD) { /* _sd_prefetch_opt == 0 */ 2695 /* CKD prefetch: bufvec not req'd, use placeholder */ 2696 bufvec->bufaddr = NULL; 2697 bufvec->bufvmeaddr = NULL; 2698 bufvec->buflen = 0; 2699 bufvec = _prefetch_sb_vec; 2700 } 2701 st_cblk = FBA_TO_BLK_NUM(fba_pos); 2702 st_cblk_off = BLK_FBA_OFF(fba_pos); 2703 st_cblk_len = BLK_FBAS - st_cblk_off; 2704 if ((nsc_size_t)st_cblk_len >= fba_len) { 2705 end_cblk_len = 0; 2706 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 2707 } else 2708 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 2709 cblk = st_cblk; 2710 2711 2712 /* 2713 * count number of blocks on chain that is required 2714 */ 2715 2716 /* middle piece */ 2717 dmchain_request_blocks = 2718 (fba_len - (st_cblk_len + end_cblk_len)) >> BLK_FBA_SHFT; 2719 2720 /* start piece */ 2721 ++dmchain_request_blocks; 2722 2723 /* end piece */ 2724 if (end_cblk_len) 2725 ++dmchain_request_blocks; 2726 2727 2728 cc_flag = 0; 2729 if ((handle->bh_flag & NSC_PINNABLE) && (handle->bh_flag & NSC_WRBUF)) 2730 cc_flag |= CC_PINNABLE; 2731 if (handle->bh_flag & (NSC_NOCACHE|NSC_SEQ_IO)) 2732 cc_flag |= CC_QHEAD; 2733 lentry = NULL; 2734 stall = 0; 2735 2736 do { 2737 pageio = ((flag & NSC_PAGEIO) != 0 || sdbc_pageio_always != 0); 2738 cget: 2739 if ((centry = (_sd_cctl_t *) 2740 _sd_hash_search(cd, cblk, _sd_htable)) != 0) { 2741 2742 if (SET_CENTRY_INUSE(centry)) { 2743 /* already inuse: wait for block, retry */ 2744 sdbc_allocb_inuse++; 2745 if (locked) 2746 rw_exit(&sdbc_queue_lock); 2747 _sd_cc_wait(cd, cblk, centry, CC_INUSE); 2748 if (locked) 2749 rw_enter(&sdbc_queue_lock, RW_WRITER); 2750 goto cget; 2751 } 2752 2753 /* 2754 * bug 4529671 2755 * now that we own the centry make sure that 2756 * it is still good. it could have been processed 2757 * by _sd_dealloc_dm() in the window between 2758 * _sd_hash_search() and SET_CENTRY_INUSE(). 2759 */ 2760 if ((_sd_cctl_t *) 2761 _sd_hash_search(cd, cblk, _sd_htable) != centry) { 2762 sdbc_allocb_deallocd++; 2763 #ifdef DEBUG 2764 cmn_err(CE_WARN, 2765 "!centry %p cd %d cblk %" NSC_SZFMT 2766 " fba_len %" NSC_SZFMT " lost to dealloc?! " 2767 "cc_data %p", (void *)centry, cd, cblk, 2768 fba_orig_len, (void *)centry->cc_data); 2769 #endif 2770 2771 CLEAR_CENTRY_INUSE(centry); 2772 goto cget; 2773 } 2774 2775 if (CC_CD_BLK_MATCH(cd, cblk, centry)) { 2776 /* 2777 * Do pagelist io mutual exclusion 2778 * before messing with the centry. 2779 */ 2780 if (pageio && SET_CENTRY_PAGEIO(centry)) { 2781 /* wait for flusher to finish pageio */ 2782 sdbc_allocb_pageio1++; 2783 2784 CLEAR_CENTRY_INUSE(centry); 2785 if (locked) 2786 rw_exit(&sdbc_queue_lock); 2787 _sd_cc_wait(cd, cblk, centry, 2788 CC_PAGEIO); 2789 if (locked) 2790 rw_enter(&sdbc_queue_lock, 2791 RW_WRITER); 2792 goto cget; 2793 } 2794 2795 sdbc_allocb_hit++; 2796 this_entry_type = HASH_ENTRY_DM; 2797 pageio = 0; 2798 centry->cc_toflush = 0; 2799 2800 centry->cc_hits++; 2801 2802 /* this will reset the age flag */ 2803 sdbc_centry_init_dm(centry); 2804 2805 DTRACE_PROBE1(_sd_alloc_buf1, 2806 _sd_cctl_t *, centry); 2807 } else { 2808 /* block mismatch: release, alloc new block */ 2809 sdbc_allocb_lost++; 2810 2811 CLEAR_CENTRY_INUSE(centry); 2812 2813 goto cget; 2814 2815 } 2816 } else { 2817 centry = sdbc_centry_alloc(cd, cblk, 2818 dmchain_request_blocks, &stall, 2819 &alloc_tok, locked ? ALLOC_LOCKED : 0); 2820 2821 /* 2822 * dmchaining adjustment. 2823 * if centry was obtained from the dmchain 2824 * then clear local pageio variable because the 2825 * centry already has cc_pageio set. 2826 */ 2827 if (CENTRY_PAGEIO(centry)) 2828 pageio = 0; 2829 2830 DTRACE_PROBE1(_sd_alloc_buf2, _sd_cctl_t *, centry); 2831 2832 this_entry_type = ELIGIBLE_ENTRY_DM; 2833 if (centry->cc_aging_dm & FOUND_IN_HASH_DM) 2834 this_entry_type = HASH_ENTRY_DM; 2835 else { 2836 if (centry->cc_aging_dm & FOUND_HOLD_OVER_DM) 2837 this_entry_type = HOLD_ENTRY_DM; 2838 } 2839 } 2840 2841 centry->cc_aging_dm &= ~(FOUND_IN_HASH_DM|FOUND_HOLD_OVER_DM); 2842 2843 /* 2844 * Do pagelist io mutual exclusion now if we did not do 2845 * it above. 2846 */ 2847 2848 if (pageio && SET_CENTRY_PAGEIO(centry)) { 2849 /* wait for flusher to finish pageio */ 2850 sdbc_allocb_pageio2++; 2851 2852 2853 CLEAR_CENTRY_INUSE(centry); 2854 if (locked) 2855 rw_exit(&sdbc_queue_lock); 2856 _sd_cc_wait(cd, cblk, centry, CC_PAGEIO); 2857 if (locked) 2858 rw_enter(&sdbc_queue_lock, RW_WRITER); 2859 goto cget; 2860 } 2861 2862 pageio = 0; 2863 2864 if (CENTRY_DIRTY(centry)) { 2865 /* 2866 * end action might set PEND_DIRTY flag 2867 * must lock if need to change flag bits 2868 */ 2869 if (centry->cc_flag != (centry->cc_flag | cc_flag)) { 2870 /* was FAST */ 2871 mutex_enter(¢ry->cc_lock); 2872 centry->cc_flag |= cc_flag; 2873 /* was FAST */ 2874 mutex_exit(¢ry->cc_lock); 2875 } 2876 } else 2877 centry->cc_flag |= cc_flag; 2878 2879 centry->cc_chain = NULL; 2880 2881 /* 2882 * step 0:check valid bits in each cache ele as 2883 * the chain grows - set ioent/io_pos to first 2884 * instance of invalid data 2885 */ 2886 if (cblk == st_cblk) { 2887 handle->bh_centry = centry; 2888 fba_len -= st_cblk_len; 2889 lentry = centry; 2890 if (flag & NSC_RDBUF) { 2891 if (!SDBC_VALID_BITS(st_cblk_off, st_cblk_len, 2892 centry)) { 2893 io_pos = fba_pos; 2894 ioent = centry; 2895 } else { 2896 DATA_LOG(SDF_ALLOC, centry, st_cblk_off, 2897 st_cblk_len); 2898 2899 DTRACE_PROBE4(_sd_alloc_data1, 2900 uint64_t, (uint64_t) 2901 (BLK_TO_FBA_NUM(cblk) + 2902 st_cblk_off), int, st_cblk_len, 2903 char *, *(int64_t *) 2904 (centry->cc_data + 2905 FBA_SIZE(st_cblk_off)), 2906 char *, *(int64_t *) 2907 (centry->cc_data + 2908 FBA_SIZE(st_cblk_off + st_cblk_len) 2909 - 8)); 2910 } 2911 } 2912 cblk++; 2913 } else if (fba_len == (nsc_size_t)end_cblk_len) { 2914 lentry->cc_chain = centry; 2915 fba_len -= end_cblk_len; 2916 if (flag & NSC_RDBUF) { 2917 if (ioent == NULL) { 2918 if (!SDBC_VALID_BITS(0, end_cblk_len, 2919 centry)) { 2920 io_pos = BLK_TO_FBA_NUM(cblk); 2921 ioent = centry; 2922 } else { 2923 DATA_LOG(SDF_ALLOC, centry, 0, 2924 end_cblk_len); 2925 2926 DTRACE_PROBE4(_sd_alloc_data2, 2927 uint64_t, 2928 BLK_TO_FBA_NUM(cblk), 2929 int, end_cblk_len, 2930 char *, *(int64_t *) 2931 (centry->cc_data), 2932 char *, *(int64_t *) 2933 (centry->cc_data + 2934 FBA_SIZE(end_cblk_len) 2935 - 8)); 2936 } 2937 } 2938 } 2939 } else { 2940 lentry->cc_chain = centry; 2941 lentry = centry; 2942 fba_len -= BLK_FBAS; 2943 if (flag & NSC_RDBUF) { 2944 if (ioent == NULL) { 2945 if (!FULLY_VALID(centry)) { 2946 io_pos = BLK_TO_FBA_NUM(cblk); 2947 ioent = centry; 2948 } else { 2949 DATA_LOG(SDF_ALLOC, centry, 0, 2950 BLK_FBAS); 2951 2952 DTRACE_PROBE4(_sd_alloc_data3, 2953 uint64_t, (uint64_t) 2954 BLK_TO_FBA_NUM(cblk), 2955 int, BLK_FBAS, 2956 char *, *(int64_t *) 2957 (centry->cc_data), 2958 char *, *(int64_t *) 2959 (centry->cc_data + 2960 FBA_SIZE(BLK_FBAS) - 8)); 2961 } 2962 } 2963 } 2964 cblk++; 2965 } 2966 2967 /* if this block has a new identity clear prefetch history */ 2968 if (this_entry_type != HASH_ENTRY_DM) 2969 centry->cc_aging_dm &= 2970 ~(PREFETCH_BUF_I | PREFETCH_BUF_E); 2971 2972 centry->cc_aging_dm &= ~(ENTRY_FIELD_DM); 2973 centry->cc_aging_dm |= this_entry_type; 2974 if (flag & NSC_METADATA) 2975 centry->cc_aging_dm |= STICKY_METADATA_DM; 2976 2977 --dmchain_request_blocks; 2978 } while (fba_len); 2979 2980 if (locked) { 2981 rw_exit(&sdbc_queue_lock); 2982 locked = 0; 2983 } 2984 2985 ASSERT(dmchain_request_blocks == 0); 2986 2987 /* 2988 * do any necessary cleanup now that all the blocks are allocated. 2989 */ 2990 sdbc_centry_alloc_end(&alloc_tok); 2991 2992 /* be sure you nul term. the chain */ 2993 centry->cc_chain = NULL; 2994 2995 /* 2996 * step one: establish HOST/PARASITE/OTHER relationships 2997 * between the centry ele in the list and calc the alloc size 2998 * (fill in CATAGORY based on TYPE and immediate neighbors) 2999 */ 3000 if (sts = _sd_setup_category_on_type(handle->bh_centry)) { 3001 #ifdef DEBUG 3002 err = _sd_free_buf(handle); 3003 if (err) { 3004 cmn_err(CE_WARN, "!sdbc(_sd_alloc_buf): _sd_free_buf " 3005 "failed: err:%d handle:%p", err, (void *)handle); 3006 } 3007 #else 3008 (void) _sd_free_buf(handle); 3009 #endif 3010 goto done; 3011 } 3012 3013 /* 3014 * step two: alloc the needed mem and fill in the data and chaining 3015 * fields (leave bufvec for step three) 3016 */ 3017 (void) _sd_setup_mem_chaining(handle->bh_centry, 0); 3018 3019 /* 3020 * step three: do the bufvec 3021 */ 3022 fba_len = fba_orig_len; 3023 centry = handle->bh_centry; 3024 bufvec = handle->bh_bufvec; 3025 3026 while (centry) { 3027 DTRACE_PROBE3(_sd_alloc_buf_centrys, _sd_cctl_t *, centry, 3028 int, cd, uint64_t, 3029 (uint64_t)BLK_TO_FBA_NUM(CENTRY_BLK(centry))); 3030 3031 if (fba_len == fba_orig_len) { 3032 bufvec->bufaddr = (centry->cc_data + 3033 FBA_SIZE(st_cblk_off)); 3034 bufvec->bufvmeaddr = 0; /* not used */ 3035 bufvec->buflen = FBA_SIZE(st_cblk_len); 3036 bufvec++; 3037 fba_len -= st_cblk_len; 3038 } else if (fba_len == (nsc_size_t)end_cblk_len) { 3039 _sd_bufvec_t *pbufvec = bufvec - 1; 3040 3041 if ((pbufvec->bufaddr + pbufvec->buflen) == 3042 centry->cc_data) { 3043 /* contiguous */ 3044 pbufvec->buflen += FBA_SIZE(end_cblk_len); 3045 } else { 3046 3047 bufvec->bufaddr = centry->cc_data; 3048 bufvec->bufvmeaddr = 0; /* not used */ 3049 bufvec->buflen = FBA_SIZE(end_cblk_len); 3050 bufvec++; 3051 } 3052 3053 fba_len -= end_cblk_len; 3054 } else { 3055 _sd_bufvec_t *pbufvec = bufvec - 1; 3056 3057 if ((pbufvec->bufaddr + pbufvec->buflen) == 3058 centry->cc_data) { 3059 /* contiguous */ 3060 pbufvec->buflen += CACHE_BLOCK_SIZE; 3061 } else { 3062 3063 bufvec->bufaddr = centry->cc_data; 3064 bufvec->bufvmeaddr = 0; /* not used */ 3065 bufvec->buflen = CACHE_BLOCK_SIZE; 3066 bufvec++; 3067 } 3068 3069 fba_len -= BLK_FBAS; 3070 } 3071 3072 centry = centry->cc_chain; 3073 } 3074 3075 /* be sure you nul term. the chain */ 3076 bufvec->bufaddr = NULL; 3077 bufvec->bufvmeaddr = 0; 3078 bufvec->buflen = 0; 3079 3080 /* frag statistics */ 3081 { 3082 _sd_bufvec_t *tbufvec; 3083 3084 for (tbufvec = handle->bh_bufvec; tbufvec != bufvec; 3085 ++tbufvec) { 3086 if ((min_frag > tbufvec->buflen) || (min_frag == 0)) 3087 min_frag = tbufvec->buflen; 3088 3089 if (max_frag < tbufvec->buflen) 3090 max_frag = tbufvec->buflen; 3091 } 3092 3093 nfrags = bufvec - handle->bh_bufvec; 3094 min_frag = FBA_LEN(min_frag); 3095 max_frag = FBA_LEN(max_frag); 3096 } 3097 3098 /* buffer memory frag stats */ 3099 DTRACE_PROBE4(_sd_alloc_buf_frag, uint64_t, (uint64_t)fba_orig_len, 3100 int, nfrags, int, min_frag, int, max_frag); 3101 3102 3103 if (flag & NSC_WRBUF) { 3104 if (_SD_IS_WRTHRU(handle)) 3105 goto alloc_done; 3106 if (_sd_alloc_write(handle->bh_centry, &stall)) { 3107 _sd_unblock(&_sd_flush_cv); 3108 handle->bh_flag |= NSC_FORCED_WRTHRU; 3109 } else { 3110 for (centry = handle->bh_centry; 3111 centry; centry = centry->cc_chain) { 3112 3113 CENTRY_SET_FTPOS(centry); 3114 SSOP_SETCENTRY(sdbc_safestore, 3115 centry->cc_write); 3116 } 3117 } 3118 } 3119 3120 alloc_done: 3121 if (locked) { 3122 rw_exit(&sdbc_queue_lock); 3123 locked = 0; 3124 } 3125 if (ioent) { 3126 _SD_DISCONNECT_CALLBACK(handle); 3127 sts = _sd_doread(handle, ioent, io_pos, 3128 (fba_pos + fba_orig_len - io_pos), flag); 3129 if (sts > 0) 3130 (void) _sd_free_buf(handle); 3131 } else 3132 if (flag & NSC_RDBUF) { 3133 CACHE_FBA_READ(cd, fba_orig_len); 3134 CACHE_READ_HIT; 3135 FBA_READ_IO_KSTATS(cd, FBA_SIZE(fba_orig_len)); 3136 3137 sts = NSC_HIT; 3138 } else 3139 sts = (stall) ? NSC_DONE : NSC_HIT; 3140 3141 SDTRACE(ST_EXIT|SDF_ALLOCBUF, cd, fba_orig_len, fba_pos, flag, sts); 3142 3143 done: 3144 if (locked) 3145 rw_exit(&sdbc_queue_lock); 3146 3147 KSTAT_RUNQ_EXIT(cd); 3148 3149 return (sts); 3150 } 3151 3152 /* 3153 * consistency checking for ccents 3154 */ 3155 3156 #define ELIGIBLE(p) (p & ELIGIBLE_ENTRY_DM) 3157 #define HOLD(p) (p & HOLD_ENTRY_DM) 3158 #define HASHE(p) (p & HASH_ENTRY_DM) 3159 3160 #define HOST(p) (p & HOST_ENTRY_DM) 3161 #define PARA(p) (p & PARASITIC_ENTRY_DM) 3162 #define OTHER(p) \ 3163 (!(p & (HOST_ENTRY_DM | PARASITIC_ENTRY_DM | ELIGIBLE_ENTRY_DM))) 3164 3165 #define AVAIL(p) (p & AVAIL_ENTRY_DM) 3166 3167 /* 3168 * sdbc_check_cctl_cot -- consistency check for _sd_setup_category_on_type() 3169 * may only be called on entry to state machine (when ccent is either 3170 * ELIGIBLE_ENTRY_DM, HOLD_ENTRY_DM or HASH_ENTRY_DM). 3171 * 3172 * print message or panic (DEBUG) if inconsistency detected. 3173 */ 3174 static int 3175 sdbc_check_cctl_cot(_sd_cctl_t *centry) 3176 { 3177 uint_t age; 3178 int size; 3179 uchar_t *data; 3180 int host_or_other; 3181 int para; 3182 int ccent_ok = 1; 3183 3184 age = centry->cc_aging_dm; 3185 size = centry->cc_alloc_size_dm; 3186 data = centry->cc_data; 3187 host_or_other = size && data; 3188 para = !size && data; 3189 3190 /* 3191 * on entry to _sd_setup_category_on_type(), 3192 * one of three mutually exclusive entry field bits must be set 3193 */ 3194 3195 switch ((age & (ELIGIBLE_ENTRY_DM | HOLD_ENTRY_DM | HASH_ENTRY_DM))) { 3196 case ELIGIBLE_ENTRY_DM: 3197 case HOLD_ENTRY_DM: 3198 case HASH_ENTRY_DM: 3199 /* ok */ 3200 break; 3201 default: 3202 /* zero or multiple flag bits */ 3203 ccent_ok = 0; 3204 break; 3205 } 3206 3207 /* categories are mutually exclusive */ 3208 if (HOST(age) && PARA(age)) 3209 ccent_ok = 0; 3210 3211 /* these bits should be cleared out (STICKY_METADATA_DM not used) */ 3212 if (age & (AVAIL_ENTRY_DM | FOUND_HOLD_OVER_DM | FOUND_IN_HASH_DM | 3213 STICKY_METADATA_DM)) 3214 ccent_ok = 0; 3215 3216 /* eligible has no data and no size */ 3217 if (ELIGIBLE(age) && (size || data)) 3218 ccent_ok = 0; 3219 3220 /* parasite has zero size and non-zero data */ 3221 if (PARA(age) && !para) 3222 ccent_ok = 0; 3223 3224 /* host has non-zero size and non-zero data */ 3225 if (HOST(age) && !host_or_other) 3226 ccent_ok = 0; 3227 3228 /* "other" is just like a host */ 3229 if (OTHER(age) && !host_or_other) 3230 ccent_ok = 0; 3231 3232 /* a HOLD or a HASH must have a size */ 3233 if ((size) && !(age & (HASH_ENTRY_DM | HOLD_ENTRY_DM))) 3234 ccent_ok = 0; 3235 3236 if (!ccent_ok) 3237 cmn_err(cmn_level, 3238 "!sdbc(sdbc_check_cctl_cot): inconsistent ccent %p " 3239 "age %x size %d data %p", (void *)centry, age, size, 3240 (void *)data); 3241 3242 return (ccent_ok); 3243 } 3244 3245 /* 3246 * sdbc_mark_cctl_cot -- mark cctls bad and invalidate when 3247 * inconsistency found in _sd_setup_category_on_type() 3248 * returns nothing 3249 * 3250 * Note: this is an error recovery path that is triggered when an 3251 * inconsistency in a cctl is detected. _sd_centry_release() will take 3252 * these cache entries out of circulation and place them on a separate list 3253 * for debugging purposes. 3254 */ 3255 void 3256 sdbc_mark_cctl_cot(_sd_cctl_t *header, _sd_cctl_t *centry) 3257 { 3258 _sd_cctl_t *cur_ent = header; 3259 3260 /* the entire chain is guilty by association */ 3261 while (cur_ent) { 3262 3263 (void) _sd_hash_delete((struct _sd_hash_hd *)cur_ent, 3264 _sd_htable); 3265 3266 cur_ent->cc_aging_dm |= BAD_CHAIN_DM; 3267 3268 cur_ent = cur_ent->cc_chain; 3269 } 3270 3271 centry->cc_aging_dm |= BAD_ENTRY_DM; /* this is the problem child */ 3272 } 3273 3274 /* 3275 * _sd_setup_category_on_type(_sd_cctl_t *) - Setup the centry CATEGORY based on 3276 * centry TYPE and immediate neighbors. Identify each eligible (ie not HASH) 3277 * centry as a host/parasite. host actually have memory allocated to 3278 * them and parasites are chained to the host and point to page offsets within 3279 * the host's memory. 3280 * 3281 * RETURNS: 3282 * 0 on success, EINTR if inconsistency detected in centry 3283 * 3284 * Note: 3285 * none 3286 */ 3287 static int 3288 _sd_setup_category_on_type(_sd_cctl_t *header) 3289 { 3290 _sd_cctl_t *prev_ent, *next_ent, *centry; 3291 _sd_cctl_t *anchor = NULL; 3292 int current_pest_count, local_max_dyn_list; 3293 int cl; 3294 int ret = 0; 3295 3296 ASSERT(header); 3297 3298 if (sdbc_use_dmchain) 3299 local_max_dyn_list = max_dm_queues - 1; 3300 else { 3301 /* pickup a fresh copy - has the world changed */ 3302 local_max_dyn_list = dynmem_processing_dm.max_dyn_list; 3303 } 3304 3305 prev_ent = 0; 3306 centry = header; 3307 next_ent = centry->cc_chain; 3308 current_pest_count = 0; 3309 cl = 2; 3310 3311 /* try to recover from bad cctl */ 3312 if (sdbc_check_cot && !sdbc_check_cctl_cot(centry)) 3313 ret = EINTR; 3314 3315 while (cl && (ret == 0)) { 3316 switch (cl) { 3317 case (1): /* chain to next/monitor for completion */ 3318 prev_ent = centry; 3319 centry = next_ent; 3320 next_ent = 0; 3321 cl = 0; 3322 if (centry) { 3323 3324 if (sdbc_check_cot && 3325 !sdbc_check_cctl_cot(centry)) { 3326 ret = EINTR; 3327 break; 3328 } 3329 3330 next_ent = centry->cc_chain; 3331 cl = 2; 3332 } 3333 break; 3334 3335 case (2): /* vector to appropriate routine */ 3336 if (!(centry->cc_aging_dm & ELIGIBLE_ENTRY_DM)) 3337 cl = 5; 3338 else if (prev_ent && (prev_ent->cc_aging_dm & 3339 ELIGIBLE_ENTRY_DM)) 3340 cl = 15; 3341 else 3342 cl = 10; 3343 break; 3344 3345 case (5): /* process NON-ELIGIBLE entries */ 3346 if (!(centry->cc_aging_dm & 3347 (HASH_ENTRY_DM|HOLD_ENTRY_DM))) { 3348 /* no catagory */ 3349 3350 /* consistency check */ 3351 if (centry->cc_alloc_size_dm || 3352 centry->cc_data) { 3353 cmn_err(cmn_level, 3354 "!sdbc(setup_cot): " 3355 "OTHER with data/size %p", 3356 (void *)centry); 3357 3358 ret = EINTR; 3359 break; 3360 } 3361 3362 centry->cc_aging_dm &= 3363 ~CATAGORY_ENTRY_DM; 3364 centry->cc_alloc_size_dm = BLK_SIZE(1); 3365 DTRACE_PROBE1(_sd_setup_category, 3366 _sd_cctl_t *, centry); 3367 } 3368 cl = 1; 3369 break; 3370 3371 /* 3372 * no prev entry (ie top of list) or no prev 3373 * ELIGIBLE entry 3374 */ 3375 case (10): 3376 /* 3377 * this is an eligible entry, does it start 3378 * a list or is it a loner 3379 */ 3380 /* consistency check */ 3381 if (centry->cc_alloc_size_dm || 3382 centry->cc_data) { 3383 cmn_err(cmn_level, "!sdbc(setup_cot): " 3384 "HOST with data/size %p", 3385 (void *)centry); 3386 ret = EINTR; 3387 break; 3388 } 3389 3390 if (next_ent && (next_ent->cc_aging_dm & 3391 ELIGIBLE_ENTRY_DM)) { 3392 3393 3394 /* it starts a list */ 3395 /* host catagory */ 3396 centry->cc_aging_dm |= HOST_ENTRY_DM; 3397 /* start out with one page */ 3398 centry->cc_alloc_size_dm = BLK_SIZE(1); 3399 anchor = centry; 3400 DTRACE_PROBE1(_sd_setup_category, 3401 _sd_cctl_t *, anchor); 3402 cl = 1; 3403 } else { 3404 /* 3405 * it's a loner 3406 * drop status to no category and 3407 * restart 3408 */ 3409 cl = 2; 3410 centry->cc_aging_dm &= 3411 ~ELIGIBLE_ENTRY_DM; 3412 } 3413 break; 3414 3415 case (15): /* default to parasite catagory */ 3416 3417 /* consistency check */ 3418 if (centry->cc_alloc_size_dm || 3419 centry->cc_data) { 3420 cmn_err(cmn_level, "!sdbc(setup_cot): " 3421 "PARA with data/size %p", 3422 (void *)centry); 3423 3424 ret = EINTR; 3425 break; 3426 } 3427 3428 if (current_pest_count < local_max_dyn_list-1) { 3429 /* continue to grow the pest list */ 3430 current_pest_count++; 3431 centry->cc_aging_dm |= 3432 PARASITIC_ENTRY_DM; 3433 3434 /* 3435 * offset of host ent mem this will pt 3436 * to 3437 */ 3438 centry->cc_alloc_size_dm = 3439 anchor->cc_alloc_size_dm; 3440 /* 3441 * up the host mem req by one for 3442 * this parasite 3443 */ 3444 DTRACE_PROBE1(_sd_setup_category, 3445 _sd_cctl_t *, centry); 3446 3447 anchor->cc_alloc_size_dm += BLK_SIZE(1); 3448 3449 cl = 1; 3450 } else { 3451 /* 3452 * term this pest list - restart fresh 3453 * on this entry 3454 */ 3455 current_pest_count = 0; 3456 prev_ent->cc_aging_dm &= 3457 ~(HOST_ENTRY_DM|ELIGIBLE_ENTRY_DM); 3458 cl = 2; 3459 } 3460 break; 3461 } /* switch(cl) */ 3462 } /* while (cl) */ 3463 3464 if (ret != 0) 3465 sdbc_mark_cctl_cot(header, centry); 3466 3467 return (ret); 3468 } 3469 3470 /* 3471 * _sd_setup_mem_chaining(_sd_cctl_t *) - Allocate memory, setup 3472 * mem ptrs an host/pest chaining. Do the actual allocation as described in 3473 * sd_setup_category_on_type(). 3474 * 3475 * RETURNS: 3476 * 0 on success 3477 * non-zero on error 3478 * 3479 * Note: 3480 * if called with ALLOC_NOWAIT, caller must check for non-zero return 3481 */ 3482 static int 3483 _sd_setup_mem_chaining(_sd_cctl_t *header, int flag) 3484 { 3485 _sd_cctl_t *prev_ent, *next_ent, *centry; 3486 _sd_cctl_t *anchor = NULL; 3487 int cl, rc = 0; 3488 3489 ASSERT(header); 3490 3491 if (!header) 3492 return (0); 3493 3494 prev_ent = 0; 3495 centry = header; 3496 next_ent = centry->cc_chain; 3497 cl = 2; 3498 while (cl) { 3499 switch (cl) { 3500 case (1): /* chain to next/monitor for completion */ 3501 centry->cc_aging_dm &= ~ELIGIBLE_ENTRY_DM; 3502 prev_ent = centry; 3503 centry = next_ent; 3504 next_ent = 0; 3505 cl = 0; 3506 if (centry) { 3507 next_ent = centry->cc_chain; 3508 cl = 2; 3509 } 3510 break; 3511 3512 case (2): /* vector to appropriate routine */ 3513 if (centry->cc_aging_dm & HOST_ENTRY_DM) 3514 cl = 10; 3515 else if (centry->cc_aging_dm & 3516 PARASITIC_ENTRY_DM) 3517 cl = 15; 3518 else 3519 cl = 5; 3520 break; 3521 3522 case (5): /* OTHER processing - alloc mem */ 3523 if (rc = sdbc_centry_memalloc_dm(centry, 3524 centry->cc_alloc_size_dm, flag)) 3525 /* The allocation failed */ 3526 cl = 0; 3527 else 3528 cl = 1; 3529 break; 3530 3531 /* 3532 * HOST entry processing - save the anchor pt, 3533 * alloc the memory, 3534 */ 3535 case (10): /* setup head and nxt ptrs */ 3536 anchor = centry; 3537 if (rc = sdbc_centry_memalloc_dm(centry, 3538 centry->cc_alloc_size_dm, flag)) 3539 /* The allocation failed */ 3540 cl = 0; 3541 else 3542 cl = 1; 3543 break; 3544 3545 /* 3546 * PARASITIC entry processing - setup w/no 3547 * memory, setup head/next ptrs, 3548 */ 3549 case (15): 3550 /* 3551 * fudge the data mem ptr to an offset from 3552 * the anchor alloc 3553 */ 3554 if (!(centry->cc_aging_dm & 3555 (HASH_ENTRY_DM| HOLD_ENTRY_DM))) { 3556 centry->cc_head_dm = anchor; 3557 3558 /* chain prev to this */ 3559 prev_ent->cc_next_dm = centry; 3560 3561 /* 3562 * generate the actual data ptr into 3563 * host entry memory 3564 */ 3565 centry->cc_data = anchor->cc_data + 3566 centry->cc_alloc_size_dm; 3567 centry->cc_alloc_size_dm = 0; 3568 } 3569 cl = 1; 3570 break; 3571 } /* switch(cl) */ 3572 } /* while (cl) */ 3573 3574 return (rc); 3575 } 3576 3577 /* 3578 * _sd_check_buffer_alloc - Check if buffer allocation is invalid. 3579 * 3580 * RETURNS: 3581 * 0 if its ok to continue with allocation. 3582 * Else errno to be returned to the user. 3583 * 3584 * Note: 3585 * This routine could block if the device is not local and 3586 * recovery is in progress. 3587 */ 3588 3589 /* ARGSUSED */ 3590 static int 3591 _sd_check_buffer_alloc(int cd, nsc_off_t fba_pos, nsc_size_t fba_len, 3592 _sd_buf_handle_t **hp) 3593 { 3594 /* 3595 * This check exists to ensure that someone will not pass in an 3596 * arbitrary pointer and try to pass it off as a handle. 3597 */ 3598 if ((*hp)->bh_flag & (~_SD_VALID_FLAGS)) { 3599 cmn_err(CE_WARN, "!sdbc(_sd_check_buffer_alloc) " 3600 "cd %d invalid handle %p flags %x", 3601 cd, (void *)*hp, (*hp)->bh_flag); 3602 return (EINVAL); 3603 } 3604 3605 if ((_sd_cache_initialized == 0) || (FILE_OPENED(cd) == 0)) { 3606 cmn_err(CE_WARN, "!sdbc(_sd_check_buffer_alloc) " 3607 "cd %d not open. Cache init %d", 3608 cd, _sd_cache_initialized); 3609 return (EINVAL); 3610 } 3611 ASSERT(cd >= 0); 3612 if (!(_sd_cache_files[cd].cd_rawfd) || 3613 !nsc_held(_sd_cache_files[cd].cd_rawfd)) { 3614 cmn_err(CE_WARN, 3615 "!sdbc(_sd_check_buffer_alloc) cd %d is not attached", cd); 3616 return (EINVAL); 3617 } 3618 3619 ASSERT_IO_SIZE(fba_pos, fba_len, cd); 3620 ASSERT_LEN(fba_len); 3621 3622 return (0); 3623 } 3624 3625 /* 3626 * sdbc_check_handle -- check that handle is valid 3627 * return 1 if ok, 0 otherwise (if debug then panic). 3628 */ 3629 static int 3630 sdbc_check_handle(_sd_buf_handle_t *handle) 3631 { 3632 int ret = 1; 3633 3634 if (!_SD_HANDLE_ACTIVE(handle)) { 3635 3636 cmn_err(cmn_level, "!sdbc(_sd_free_buf): invalid handle %p" 3637 "cd %d fpos %" NSC_SZFMT " flen %" NSC_SZFMT " flag %x", 3638 (void *)handle, HANDLE_CD(handle), handle->bh_fba_pos, 3639 handle->bh_fba_len, handle->bh_flag); 3640 3641 ret = 0; 3642 } 3643 3644 return (ret); 3645 } 3646 3647 /* 3648 * _sd_free_buf - Free the buffers allocated in _sd_alloc_buf. 3649 * 3650 * ARGUMENTS: 3651 * handle - The handle allocated in _sd_alloc_buf. 3652 * 3653 * RETURNS: 3654 * 0 on success. 3655 * Else errno. 3656 * 3657 * NOTE: 3658 * If handle was allocated through _sd_alloc_buf, the handle allocated 3659 * flag (NSC_HALLOCATED) will be reset by _sd_alloc_buf. This indicates 3660 * that _sd_free_buf should free up the handle as well. 3661 * All other handles directly allocated from _sd_alloc_handle will have 3662 * that flag set. Any handle with valid blocks will have the handle 3663 * active flag. It is an error if the active flag is not set. 3664 * (if free_buf were called without going through alloc_buf) 3665 */ 3666 3667 int 3668 _sd_free_buf(_sd_buf_handle_t *handle) 3669 { 3670 _sd_cctl_t *centry, *cc_chain; 3671 int cd = HANDLE_CD(handle); 3672 int flen = handle->bh_fba_len; 3673 int fpos = handle->bh_fba_pos; 3674 3675 SDTRACE(ST_ENTER|SDF_FREEBUF, HANDLE_CD(handle), 3676 handle->bh_fba_len, handle->bh_fba_pos, 0, 0); 3677 3678 if (sdbc_check_handle(handle) == 0) 3679 return (EINVAL); 3680 3681 if (handle->bh_flag & NSC_MIXED) { 3682 /* 3683 * Data in this handle will be a mix of data from the 3684 * source device and data from another device, so 3685 * invalidate all the blocks. 3686 */ 3687 handle->bh_flag &= ~NSC_QUEUE; 3688 centry = handle->bh_centry; 3689 while (centry) { 3690 centry->cc_valid = 0; 3691 centry = centry->cc_chain; 3692 } 3693 } 3694 3695 if ((handle->bh_flag & NSC_QUEUE)) { 3696 handle->bh_flag &= ~NSC_QUEUE; 3697 _sd_queue_write(handle, handle->bh_fba_pos, handle->bh_fba_len); 3698 } 3699 3700 handle->bh_flag &= ~NSC_HACTIVE; 3701 3702 centry = handle->bh_centry; 3703 while (centry) { 3704 cc_chain = centry->cc_chain; 3705 _sd_centry_release(centry); 3706 centry = cc_chain; 3707 } 3708 3709 /* 3710 * help prevent dup call to _sd_centry_release if this handle 3711 * is erroneously _sd_free_buf'd twice. (should not happen). 3712 */ 3713 handle->bh_centry = NULL; 3714 3715 if ((handle->bh_flag & NSC_HALLOCATED) == 0) { 3716 handle->bh_flag |= NSC_HALLOCATED; 3717 (void) _sd_free_handle(handle); 3718 } else { 3719 handle->bh_flag = NSC_HALLOCATED; 3720 } 3721 3722 SDTRACE(ST_EXIT|SDF_FREEBUF, cd, flen, fpos, 0, 0); 3723 3724 return (0); 3725 } 3726 3727 3728 static int _sd_lruq_srch = 0x2000; 3729 3730 /* 3731 * sdbc_get_dmchain -- get a candidate centry chain pointing to 3732 * contiguous memory 3733 * ARGUMENTS: 3734 * cblocks - number of cache blocks requested 3735 * stall - pointer to stall count (no blocks avail) 3736 * flag - ALLOC_NOWAIT flag 3737 * 3738 * RETURNS: 3739 * a cache entry or possible NULL if ALLOC_NOWAIT set 3740 * USAGE: 3741 * attempt to satisfy entire request from queue 3742 * that has no memory allocated. 3743 * if this fails then attempt a partial allocation 3744 * with a preallocated block of requested size up to 3745 * max_dyn_list. 3746 * then look for largest chain less than max_dyn_list. 3747 */ 3748 static _sd_cctl_t * 3749 sdbc_get_dmchain(int cblocks, int *stall, int flag) 3750 { 3751 _sd_cctl_t *cc_dmchain = NULL; 3752 _sd_queue_t *q; 3753 _sd_cctl_t *qhead; 3754 int num_tries; 3755 int cblocks_orig = cblocks; 3756 int nowait = flag & ALLOC_NOWAIT; 3757 int i; 3758 3759 num_tries = _sd_lruq_srch; 3760 3761 ASSERT(cblocks != 0); 3762 3763 while (!cc_dmchain) { 3764 /* get it from the os if possible */ 3765 q = &sdbc_dm_queues[0]; 3766 qhead = &(q->sq_qhead); 3767 3768 if (q->sq_inq >= cblocks) { 3769 mutex_enter(&q->sq_qlock); 3770 if (q->sq_inq >= cblocks) { 3771 _sd_cctl_t *cc_ent; 3772 3773 cc_dmchain = qhead->cc_next; 3774 3775 /* 3776 * set the inuse and pageio bits 3777 * Note: this code expects the cc_ent to 3778 * be available. no other thread may set the 3779 * inuse or pageio bit for an entry on the 3780 * 0 queue. 3781 */ 3782 cc_ent = qhead; 3783 for (i = 0; i < cblocks; ++i) { 3784 cc_ent = cc_ent->cc_next; 3785 3786 if (SET_CENTRY_INUSE(cc_ent)) { 3787 cmn_err(CE_PANIC, 3788 "centry inuse on 0 q! %p", 3789 (void *)cc_ent); 3790 } 3791 3792 if (SET_CENTRY_PAGEIO(cc_ent)) { 3793 cmn_err(CE_PANIC, 3794 "centry pageio on 0 q! %p", 3795 (void *)cc_ent); 3796 } 3797 } 3798 /* got a dmchain */ 3799 3800 /* remove this chain from the 0 queue */ 3801 cc_dmchain->cc_prev->cc_next = cc_ent->cc_next; 3802 cc_ent->cc_next->cc_prev = cc_dmchain->cc_prev; 3803 cc_dmchain->cc_prev = NULL; 3804 cc_ent->cc_next = NULL; 3805 3806 q->sq_inq -= cblocks; 3807 3808 ASSERT(GOOD_LRUSIZE(q)); 3809 3810 } 3811 mutex_exit(&q->sq_qlock); 3812 if (cc_dmchain) 3813 continue; 3814 } 3815 3816 /* look for a pre-allocated block of the requested size */ 3817 3818 3819 if (cblocks > (max_dm_queues - 1)) 3820 cblocks = max_dm_queues - 1; 3821 3822 q = &sdbc_dm_queues[cblocks]; 3823 qhead = &(q->sq_qhead); 3824 3825 if (q->sq_inq != 0) { 3826 _sd_cctl_t *tmp_dmchain; 3827 3828 mutex_enter(&q->sq_qlock); 3829 3830 for (tmp_dmchain = qhead->cc_next; tmp_dmchain != qhead; 3831 tmp_dmchain = tmp_dmchain->cc_next) { 3832 3833 /* 3834 * get a dmchain 3835 * set the inuse and pageio bits 3836 */ 3837 if (sdbc_dmchain_avail(tmp_dmchain)) { 3838 /* put on MRU end of queue */ 3839 sdbc_requeue_dmchain(q, tmp_dmchain, 3840 1, 0); 3841 cc_dmchain = tmp_dmchain; 3842 break; 3843 } 3844 sdbc_dmchain_not_avail++; 3845 } 3846 3847 mutex_exit(&q->sq_qlock); 3848 if (cc_dmchain) 3849 continue; 3850 } 3851 3852 /* 3853 * spin block 3854 * nudge the deallocator, accelerate ageing 3855 */ 3856 3857 mutex_enter(&dynmem_processing_dm.thread_dm_lock); 3858 cv_broadcast(&dynmem_processing_dm.thread_dm_cv); 3859 mutex_exit(&dynmem_processing_dm.thread_dm_lock); 3860 3861 if (nowait) 3862 break; 3863 3864 if (!(--num_tries)) { 3865 delay(drv_usectohz(20000)); 3866 (void) (*stall)++; 3867 num_tries = _sd_lruq_srch; 3868 cblocks = cblocks_orig; 3869 } else { /* see if smaller request size is available */ 3870 if (!(--cblocks)) 3871 cblocks = cblocks_orig; 3872 } 3873 3874 } /* while (!cc_dmchain) */ 3875 3876 return (cc_dmchain); 3877 } 3878 3879 static int 3880 sdbc_dmchain_avail(_sd_cctl_t *cc_ent) 3881 { 3882 int chain_avail = 1; 3883 _sd_cctl_t *anchor = cc_ent; 3884 3885 while (cc_ent) { 3886 3887 ASSERT(_sd_cctl_valid(cc_ent)); 3888 3889 if (cc_ent->cc_aging_dm & BAD_CHAIN_DM) { 3890 chain_avail = 0; 3891 break; 3892 } 3893 3894 if (CENTRY_DIRTY(cc_ent)) { 3895 chain_avail = 0; 3896 break; 3897 } 3898 if (SET_CENTRY_INUSE(cc_ent)) { 3899 chain_avail = 0; 3900 break; 3901 } 3902 3903 if ((SET_CENTRY_PAGEIO(cc_ent))) { 3904 3905 CLEAR_CENTRY_INUSE(cc_ent); 3906 chain_avail = 0; 3907 break; 3908 } 3909 3910 if (CENTRY_DIRTY(cc_ent)) { 3911 3912 CLEAR_CENTRY_PAGEIO(cc_ent); 3913 CLEAR_CENTRY_INUSE(cc_ent); 3914 chain_avail = 0; 3915 break; 3916 } 3917 3918 cc_ent->cc_flag = 0; 3919 cc_ent->cc_toflush = 0; 3920 3921 cc_ent = cc_ent->cc_next_dm; 3922 } 3923 3924 if (!chain_avail) 3925 sdbc_clear_dmchain(anchor, cc_ent); 3926 else { 3927 cc_ent = anchor; 3928 3929 /* 3930 * prevent possible deadlocks in _sd_cc_wait(): 3931 * remove from hash and wakeup any waiters now that we 3932 * have acquired the chain. 3933 */ 3934 while (cc_ent) { 3935 (void) _sd_hash_delete((struct _sd_hash_hd *)cc_ent, 3936 _sd_htable); 3937 3938 mutex_enter(&cc_ent->cc_lock); 3939 if (cc_ent->cc_await_use) { 3940 cv_broadcast(&cc_ent->cc_blkcv); 3941 } 3942 mutex_exit(&cc_ent->cc_lock); 3943 3944 cc_ent->cc_creat = nsc_lbolt(); 3945 cc_ent->cc_hits = 0; 3946 3947 cc_ent = cc_ent->cc_next_dm; 3948 } 3949 } 3950 3951 return (chain_avail); 3952 } 3953 3954 static void 3955 sdbc_clear_dmchain(_sd_cctl_t *cc_ent_start, _sd_cctl_t *cc_ent_end) 3956 { 3957 _sd_cctl_t *cc_ent = cc_ent_start; 3958 _sd_cctl_t *prev_ent; 3959 3960 ASSERT(_sd_cctl_valid(cc_ent)); 3961 3962 while (cc_ent != cc_ent_end) { 3963 3964 ASSERT(_sd_cctl_valid(cc_ent)); 3965 3966 prev_ent = cc_ent; 3967 cc_ent = cc_ent->cc_next_dm; 3968 3969 CLEAR_CENTRY_PAGEIO(prev_ent); 3970 CLEAR_CENTRY_INUSE(prev_ent); 3971 } 3972 3973 } 3974 3975 /* 3976 * put a dmchain on the LRU end of a queue 3977 */ 3978 void 3979 sdbc_ins_dmqueue_front(_sd_queue_t *q, _sd_cctl_t *cc_ent) 3980 { 3981 _sd_cctl_t *qhead = &(q->sq_qhead); 3982 3983 ASSERT(_sd_cctl_valid(cc_ent)); 3984 3985 mutex_enter(&q->sq_qlock); 3986 cc_ent->cc_next = qhead->cc_next; 3987 cc_ent->cc_prev = qhead; 3988 qhead->cc_next->cc_prev = cc_ent; 3989 qhead->cc_next = cc_ent; 3990 q->sq_inq++; 3991 cc_ent->cc_cblocks = q->sq_dmchain_cblocks; 3992 3993 ASSERT(GOOD_LRUSIZE(q)); 3994 3995 mutex_exit(&q->sq_qlock); 3996 3997 } 3998 3999 /* 4000 * put a dmchain on the MRU end of a queue 4001 */ 4002 static void 4003 sdbc_ins_dmqueue_back(_sd_queue_t *q, _sd_cctl_t *cc_ent) 4004 { 4005 _sd_cctl_t *qhead = &(q->sq_qhead); 4006 4007 ASSERT(_sd_cctl_valid(cc_ent)); 4008 4009 mutex_enter(&q->sq_qlock); 4010 cc_ent->cc_next = qhead; 4011 cc_ent->cc_prev = qhead->cc_prev; 4012 qhead->cc_prev->cc_next = cc_ent; 4013 qhead->cc_prev = cc_ent; 4014 cc_ent->cc_seq = q->sq_seq++; 4015 q->sq_inq++; 4016 cc_ent->cc_cblocks = q->sq_dmchain_cblocks; 4017 4018 ASSERT(GOOD_LRUSIZE(q)); 4019 4020 mutex_exit(&q->sq_qlock); 4021 4022 } 4023 4024 /* 4025 * remove dmchain from a queue 4026 */ 4027 void 4028 sdbc_remq_dmchain(_sd_queue_t *q, _sd_cctl_t *cc_ent) 4029 { 4030 4031 ASSERT(_sd_cctl_valid(cc_ent)); 4032 4033 mutex_enter(&q->sq_qlock); 4034 cc_ent->cc_prev->cc_next = cc_ent->cc_next; 4035 cc_ent->cc_next->cc_prev = cc_ent->cc_prev; 4036 cc_ent->cc_next = cc_ent->cc_prev = NULL; /* defensive programming */ 4037 cc_ent->cc_cblocks = -1; /* indicate not on any queue */ 4038 4039 q->sq_inq--; 4040 4041 ASSERT(GOOD_LRUSIZE(q)); 4042 4043 mutex_exit(&q->sq_qlock); 4044 4045 } 4046 4047 /* 4048 * requeue a dmchain to the MRU end of its queue. 4049 * if getlock is 0 on entry the queue lock (sq_qlock) must be held 4050 */ 4051 void 4052 sdbc_requeue_dmchain(_sd_queue_t *q, _sd_cctl_t *cc_ent, int mru, 4053 int getlock) 4054 { 4055 _sd_cctl_t *qhead = &(q->sq_qhead); 4056 4057 4058 ASSERT(_sd_cctl_valid(cc_ent)); 4059 4060 if (getlock) 4061 mutex_enter(&q->sq_qlock); 4062 4063 /* inline of sdbc_remq_dmchain() */ 4064 cc_ent->cc_prev->cc_next = cc_ent->cc_next; 4065 cc_ent->cc_next->cc_prev = cc_ent->cc_prev; 4066 4067 if (mru) { /* put on MRU end of queue */ 4068 /* inline of sdbc_ins_dmqueue_back */ 4069 cc_ent->cc_next = qhead; 4070 cc_ent->cc_prev = qhead->cc_prev; 4071 qhead->cc_prev->cc_next = cc_ent; 4072 qhead->cc_prev = cc_ent; 4073 cc_ent->cc_seq = q->sq_seq++; 4074 (q->sq_req_stat)++; 4075 } else { /* put on LRU end of queue i.e. requeue to head */ 4076 /* inline of sdbc_ins_dmqueue_front */ 4077 cc_ent->cc_next = qhead->cc_next; 4078 cc_ent->cc_prev = qhead; 4079 qhead->cc_next->cc_prev = cc_ent; 4080 qhead->cc_next = cc_ent; 4081 cc_ent->cc_seq = q->sq_seq++; 4082 4083 /* 4084 * clear the CC_QHEAD bit on all members of the chain 4085 */ 4086 { 4087 _sd_cctl_t *tcent; 4088 4089 for (tcent = cc_ent; tcent; tcent = tcent->cc_next_dm) 4090 tcent->cc_flag &= ~CC_QHEAD; 4091 } 4092 } 4093 4094 if (getlock) 4095 mutex_exit(&q->sq_qlock); 4096 4097 } 4098 4099 /* 4100 * sdbc_dmchain_dirty(cc_ent) 4101 * return first dirty cc_ent in dmchain, NULL if chain is not dirty 4102 */ 4103 static _sd_cctl_t * 4104 sdbc_dmchain_dirty(_sd_cctl_t *cc_ent) 4105 { 4106 for (/* CSTYLED */; cc_ent; cc_ent = cc_ent->cc_next_dm) 4107 if (CENTRY_DIRTY(cc_ent)) 4108 break; 4109 4110 return (cc_ent); 4111 } 4112 4113 /* 4114 * sdbc_requeue_head_dm_try() 4115 * attempt to requeue a dmchain to the head of the queue 4116 */ 4117 void 4118 sdbc_requeue_head_dm_try(_sd_cctl_t *cc_ent) 4119 { 4120 int qidx; 4121 _sd_queue_t *q; 4122 4123 if (!sdbc_dmchain_dirty(cc_ent)) { 4124 qidx = cc_ent->cc_cblocks; 4125 q = &sdbc_dm_queues[qidx]; 4126 sdbc_requeue_dmchain(q, cc_ent, 0, 1); /* requeue head */ 4127 } 4128 } 4129 4130 /* 4131 * sdbc_centry_alloc_blks -- allocate cache entries with memory 4132 * 4133 * ARGUMENTS: 4134 * cd - Cache descriptor (from a previous open) 4135 * cblk - cache block number. 4136 * reqblks - number of cache blocks to be allocated 4137 * flag - can be ALLOC_NOWAIT 4138 * RETURNS: 4139 * A cache block chain or NULL if ALLOC_NOWAIT and request fails 4140 * 4141 * Note: caller must check for null return if called with 4142 * ALLOC_NOWAIT set. 4143 */ 4144 _sd_cctl_t * 4145 sdbc_centry_alloc_blks(int cd, nsc_off_t cblk, nsc_size_t reqblks, int flag) 4146 { 4147 sdbc_allocbuf_t alloc_tok = {0}; /* must be 0 */ 4148 int stall = 0; 4149 _sd_cctl_t *centry = NULL; 4150 _sd_cctl_t *lentry = NULL; 4151 _sd_cctl_t *anchor = NULL; 4152 _sd_cctl_t *next_centry; 4153 4154 ASSERT(reqblks); 4155 4156 while (reqblks) { 4157 centry = sdbc_centry_alloc(cd, cblk, reqblks, &stall, 4158 &alloc_tok, flag); 4159 4160 if (!centry) 4161 break; 4162 4163 centry->cc_chain = NULL; 4164 4165 if (lentry == NULL) 4166 anchor = centry; 4167 else 4168 lentry->cc_chain = centry; 4169 4170 lentry = centry; 4171 4172 centry->cc_aging_dm &= ~(ENTRY_FIELD_DM); 4173 4174 if (centry->cc_aging_dm & FOUND_IN_HASH_DM) 4175 centry->cc_aging_dm |= HASH_ENTRY_DM; 4176 else 4177 if (centry->cc_aging_dm & FOUND_HOLD_OVER_DM) 4178 centry->cc_aging_dm |= HOLD_ENTRY_DM; 4179 else 4180 centry->cc_aging_dm |= ELIGIBLE_ENTRY_DM; 4181 4182 centry->cc_aging_dm &= ~(FOUND_IN_HASH_DM|FOUND_HOLD_OVER_DM); 4183 --reqblks; 4184 } 4185 4186 sdbc_centry_alloc_end(&alloc_tok); 4187 4188 if (reqblks || (_sd_setup_category_on_type(anchor))) { 4189 centry = anchor; 4190 while (centry) { 4191 next_centry = centry->cc_chain; 4192 _sd_centry_release(centry); 4193 centry = next_centry; 4194 } 4195 anchor = NULL; 4196 4197 } else 4198 /* This is where the memory is actually allocated */ 4199 if (_sd_setup_mem_chaining(anchor, flag)) 4200 anchor = NULL; 4201 4202 return (anchor); 4203 } 4204 4205 4206 /* 4207 * sdbc_centry_alloc - sdbc internal function to allocate a new cache block. 4208 * 4209 * ARGUMENTS: 4210 * cd - Cache descriptor (from a previous open) 4211 * cblk - cache block number. 4212 * stall - pointer to stall count (no blocks avail) 4213 * req_blocks - number of cache blocks remaining in caller's i/o request 4214 * alloc_tok - pointer to token initialized to 0 on first call to function 4215 * flag - lock status of sdbc_queue_lock or ALLOC_NOWAIT flag 4216 * RETURNS: 4217 * A cache block, or possibly NULL if ALLOC_NOWAIT set . 4218 * 4219 * USAGE: 4220 * switch to the appropriate allocation function. 4221 * this function is used when callers need more than one cache block. 4222 * it is called repeatedly until the entire request is satisfied, 4223 * at which time the caller will then do the memory allocation. 4224 * if only one cache block is needed callers may use 4225 * sdbc_centry_alloc_blks() which also allocates memory. 4226 * 4227 * Note: caller must check for null return if called with 4228 * ALLOC_NOWAIT set. 4229 */ 4230 4231 _sd_cctl_t * 4232 sdbc_centry_alloc(int cd, nsc_off_t cblk, nsc_size_t req_blocks, int *stall, 4233 sdbc_allocbuf_t *alloc_tok, int flag) 4234 { 4235 _sd_cctl_t *centry; 4236 4237 if (sdbc_use_dmchain) 4238 centry = sdbc_alloc_dmc(cd, cblk, req_blocks, stall, alloc_tok, 4239 flag); 4240 else 4241 centry = sdbc_alloc_lru(cd, cblk, stall, flag); 4242 4243 return (centry); 4244 } 4245 4246 /* 4247 * sdbc_alloc_dmc -- allocate a centry from a dmchain 4248 * 4249 * ARGUMENTS: 4250 * cd - Cache descriptor (from a previous open) 4251 * cblk - cache block number. 4252 * stall - pointer to stall count (no blocks avail) 4253 * req_blocks - number of cache blocks in clients i/o request 4254 * alloc_tok - pointer to token initialized to 0 on first call to function 4255 * flag - lock status of sdbc_queue_lock, or ALLOC_NOWAIT flag 4256 * RETURNS: 4257 * A cache block or possibly NULL if ALLOC_NOWAIT set 4258 * 4259 * USAGE: 4260 * if dmchain is empty, allocate one. 4261 */ 4262 static _sd_cctl_t * 4263 sdbc_alloc_dmc(int cd, nsc_off_t cblk, nsc_size_t req_blocks, int *stall, 4264 sdbc_allocbuf_t *alloc_tok, int flag) 4265 { 4266 sdbc_allocbuf_impl_t *dmc = (sdbc_allocbuf_impl_t *)alloc_tok; 4267 _sd_cctl_t *centry = NULL; 4268 4269 if (!dmc->sab_dmchain) { 4270 /* 4271 * Note - sdbc_get_dmchain() returns 4272 * with cc_inuse and cc_pageio set 4273 * for all members of dmchain. 4274 */ 4275 if (dmc->sab_dmchain = 4276 sdbc_get_dmchain(req_blocks, stall, flag)) { 4277 4278 /* remember q it came from */ 4279 if (dmc->sab_dmchain->cc_alloc_size_dm) 4280 dmc->sab_q = dmc->sab_dmchain->cc_cblocks; 4281 } 4282 } 4283 4284 /* 4285 * Note: dmchain pointer is advanced in sdbc_alloc_from_dmchain() 4286 */ 4287 if (dmc->sab_dmchain) /* could be NULL if ALLOC_NOWAIT set */ 4288 centry = sdbc_alloc_from_dmchain(cd, cblk, alloc_tok, flag); 4289 4290 return (centry); 4291 } 4292 4293 /* 4294 * sdbc_alloc_from_dmchain -- allocate centry from a dmchain of centrys 4295 * 4296 * ARGUMENTS: 4297 * cd - Cache descriptor (from a previous open) 4298 * cblk - cache block number. 4299 * alloc_tok - pointer to token 4300 * flag - lock status of sdbc_queue_lock or ALLOC_NOWAIT 4301 * 4302 * RETURNS: 4303 * A cache block or possibly NULL if ALLOC_NOWAIT set. 4304 * 4305 * USAGE: 4306 * This routine allocates a new cache block from the supplied dmchain. 4307 * Assumes that dmchain is non-NULL and that all cache entries in 4308 * the dmchain have been removed from hash and have their cc_inuse and 4309 * cc_pageio bits set. 4310 */ 4311 static _sd_cctl_t * 4312 sdbc_alloc_from_dmchain(int cd, nsc_off_t cblk, sdbc_allocbuf_t *alloc_tok, 4313 int flag) 4314 { 4315 _sd_cctl_t *cc_ent, *old_ent; 4316 int categorize_centry; 4317 int locked = flag & ALLOC_LOCKED; 4318 int nowait = flag & ALLOC_NOWAIT; 4319 sdbc_allocbuf_impl_t *dmc = (sdbc_allocbuf_impl_t *)alloc_tok; 4320 4321 SDTRACE(ST_ENTER|SDF_ENT_ALLOC, cd, 0, BLK_TO_FBA_NUM(cblk), 0, 0); 4322 4323 ASSERT(dmc->sab_dmchain); 4324 4325 cc_ent = dmc->sab_dmchain; 4326 4327 ASSERT(_sd_cctl_valid(cc_ent)); 4328 4329 cc_ent->cc_valid = 0; 4330 categorize_centry = 0; 4331 if (cc_ent->cc_data) 4332 categorize_centry = FOUND_HOLD_OVER_DM; 4333 4334 alloc_try: 4335 if (cd == _CD_NOHASH) 4336 CENTRY_BLK(cc_ent) = cblk; 4337 else if ((old_ent = (_sd_cctl_t *) 4338 _sd_hash_insert(cd, cblk, (struct _sd_hash_hd *)cc_ent, 4339 _sd_htable)) != cc_ent) { 4340 4341 if (SET_CENTRY_INUSE(old_ent)) { 4342 sdbc_centry_inuse++; 4343 4344 if (nowait) { 4345 cc_ent = NULL; 4346 goto out; 4347 } 4348 4349 if (locked) 4350 rw_exit(&sdbc_queue_lock); 4351 _sd_cc_wait(cd, cblk, old_ent, CC_INUSE); 4352 if (locked) 4353 rw_enter(&sdbc_queue_lock, RW_WRITER); 4354 goto alloc_try; 4355 } 4356 4357 /* 4358 * bug 4529671 4359 * now that we own the centry make sure that 4360 * it is still good. it could have been processed 4361 * by _sd_dealloc_dm() in the window between 4362 * _sd_hash_insert() and SET_CENTRY_INUSE(). 4363 */ 4364 if ((_sd_cctl_t *)_sd_hash_search(cd, cblk, _sd_htable) 4365 != old_ent) { 4366 sdbc_centry_deallocd++; 4367 #ifdef DEBUG 4368 cmn_err(CE_WARN, "!cc_ent %p cd %d cblk %" NSC_SZFMT 4369 " lost to dealloc?! cc_data %p", (void *)old_ent, 4370 cd, cblk, (void *)old_ent->cc_data); 4371 #endif 4372 4373 CLEAR_CENTRY_INUSE(old_ent); 4374 4375 if (nowait) { 4376 cc_ent = NULL; 4377 goto out; 4378 } 4379 4380 goto alloc_try; 4381 } 4382 4383 if (CC_CD_BLK_MATCH(cd, cblk, old_ent)) { 4384 sdbc_centry_hit++; 4385 old_ent->cc_toflush = 0; 4386 /* _sd_centry_release(cc_ent); */ 4387 cc_ent = old_ent; 4388 categorize_centry = FOUND_IN_HASH_DM; 4389 } else { 4390 sdbc_centry_lost++; 4391 4392 CLEAR_CENTRY_INUSE(old_ent); 4393 4394 if (nowait) { 4395 cc_ent = NULL; 4396 goto out; 4397 } 4398 4399 goto alloc_try; 4400 } 4401 } 4402 4403 /* 4404 * advance the dmchain pointer, but only if we got the 4405 * cc_ent from the dmchain 4406 */ 4407 if (categorize_centry != FOUND_IN_HASH_DM) { 4408 if (cc_ent->cc_data) 4409 dmc->sab_dmchain = dmc->sab_dmchain->cc_next_dm; 4410 else 4411 dmc->sab_dmchain = dmc->sab_dmchain->cc_next; 4412 } 4413 4414 4415 SDTRACE(ST_EXIT|SDF_ENT_ALLOC, cd, 0, BLK_TO_FBA_NUM(cblk), 0, 0); 4416 4417 mutex_enter(&cc_ent->cc_lock); 4418 if (cc_ent->cc_await_use) { 4419 cv_broadcast(&cc_ent->cc_blkcv); 4420 } 4421 mutex_exit(&cc_ent->cc_lock); 4422 4423 sdbc_centry_init_dm(cc_ent); 4424 4425 cc_ent->cc_aging_dm |= categorize_centry; 4426 4427 out: 4428 4429 SDTRACE(ST_INFO|SDF_ENT_ALLOC, cd, 0, BLK_TO_FBA_NUM(cblk), 0, 0); 4430 4431 return (cc_ent); 4432 } 4433 4434 /* 4435 * sdbc_centry_alloc_end -- tidy up after all cache blocks have been 4436 * allocated for a request 4437 * ARGUMENTS: 4438 * alloc_tok - pointer to allocation token 4439 * RETURNS 4440 * nothing 4441 * USAGE: 4442 * at this time only useful when sdbc_use_dmchain is true. 4443 * if there are cache blocks remaining on the chain then the inuse and 4444 * pageio bits must be cleared (they were set in sdbc_get_dmchain(). 4445 * 4446 */ 4447 static void 4448 sdbc_centry_alloc_end(sdbc_allocbuf_t *alloc_tok) 4449 { 4450 _sd_cctl_t *next_centry; 4451 _sd_cctl_t *prev_centry; 4452 _sd_queue_t *q; 4453 sdbc_allocbuf_impl_t *dmc = (sdbc_allocbuf_impl_t *)alloc_tok; 4454 #ifdef DEBUG 4455 int chainpull = 0; 4456 #endif 4457 4458 if (!sdbc_use_dmchain) 4459 return; 4460 4461 next_centry = dmc->sab_dmchain; 4462 4463 while (next_centry != NULL) { 4464 CLEAR_CENTRY_PAGEIO(next_centry); 4465 4466 prev_centry = next_centry; 4467 4468 if (next_centry->cc_data) { 4469 #ifdef DEBUG 4470 ++chainpull; 4471 #endif 4472 next_centry = next_centry->cc_next_dm; 4473 4474 /* clear bit after final reference */ 4475 4476 CLEAR_CENTRY_INUSE(prev_centry); 4477 } else { 4478 next_centry = next_centry->cc_next; 4479 4480 /* 4481 * a floater from the 0 queue, insert on q. 4482 * 4483 * since this centry is not on any queue 4484 * the inuse bit can be cleared before 4485 * inserting on the q. this is also required 4486 * since sdbc_get_dmchain() does not expect 4487 * inuse bits to be set on 0 queue entry's. 4488 */ 4489 4490 CLEAR_CENTRY_INUSE(prev_centry); 4491 q = &sdbc_dm_queues[0]; 4492 sdbc_ins_dmqueue_front(q, prev_centry); 4493 } 4494 } 4495 4496 #ifdef DEBUG 4497 /* compute wastage stats */ 4498 ASSERT((chainpull >= 0) && (chainpull < max_dm_queues)); 4499 if (chainpull) 4500 (*(dmchainpull_table + (dmc->sab_q * 4501 max_dm_queues + chainpull)))++; 4502 #endif 4503 4504 } 4505 4506 4507 /* 4508 * sdbc_alloc_lru - allocate a new cache block from the lru queue 4509 * 4510 * ARGUMENTS: 4511 * cd - Cache descriptor (from a previous open) 4512 * cblk - cache block number. 4513 * stall - pointer to stall count (no blocks avail) 4514 * flag - lock status of sdbc_queue_lock or ALLOC_NOWAIT 4515 * 4516 * RETURNS: 4517 * A cache block or NULL if ALLOC_NOWAIT specified 4518 * 4519 * USAGE: 4520 * This routine allocates a new cache block from the lru. 4521 * If an allocation cannot be done, we block, unless ALLOC_NOWAIT is set. 4522 */ 4523 4524 static _sd_cctl_t * 4525 sdbc_alloc_lru(int cd, nsc_off_t cblk, int *stall, int flag) 4526 { 4527 _sd_cctl_t *cc_ent, *old_ent, *ccnext; 4528 _sd_queue_t *q = _SD_LRU_Q; 4529 _sd_cctl_t *qhead = &(q->sq_qhead); 4530 int tries = 0, num_tries; 4531 int categorize_centry; 4532 int locked = flag & ALLOC_LOCKED; 4533 int nowait = flag & ALLOC_NOWAIT; 4534 4535 if (nowait) { 4536 num_tries = q->sq_inq / 100; /* only search 1% of q */ 4537 4538 if (num_tries <= 0) /* ensure num_tries is non-zero */ 4539 num_tries = q->sq_inq; 4540 } else 4541 num_tries = _sd_lruq_srch; 4542 4543 SDTRACE(ST_ENTER|SDF_ENT_ALLOC, cd, 0, BLK_TO_FBA_NUM(cblk), 0, 0); 4544 retry_alloc_centry: 4545 4546 for (cc_ent = (qhead->cc_next); cc_ent != qhead; cc_ent = ccnext) { 4547 if (--num_tries <= 0) 4548 if (nowait) { 4549 cc_ent = NULL; 4550 goto out; 4551 } else 4552 break; 4553 4554 ccnext = cc_ent->cc_next; 4555 4556 if (cc_ent->cc_aging_dm & BAD_CHAIN_DM) 4557 continue; 4558 4559 if (CENTRY_DIRTY(cc_ent)) 4560 continue; 4561 if (SET_CENTRY_INUSE(cc_ent)) 4562 continue; 4563 4564 if (CENTRY_DIRTY(cc_ent)) { 4565 sdbc_centry_lost++; 4566 4567 CLEAR_CENTRY_INUSE(cc_ent); 4568 continue; 4569 } 4570 cc_ent->cc_flag = 0; /* CC_INUSE */ 4571 cc_ent->cc_toflush = 0; 4572 4573 /* 4574 * Inlined requeue of the LRU. (should match _sd_requeue) 4575 */ 4576 /* was FAST */ 4577 mutex_enter(&q->sq_qlock); 4578 #if defined(_SD_DEBUG) 4579 if (1) { 4580 _sd_cctl_t *cp, *cn, *qp; 4581 cp = cc_ent->cc_prev; 4582 cn = cc_ent->cc_next; 4583 qp = (q->sq_qhead).cc_prev; 4584 if (!_sd_cctl_valid(cc_ent) || 4585 (cp != &(q->sq_qhead) && !_sd_cctl_valid(cp)) || 4586 (cn != &(q->sq_qhead) && !_sd_cctl_valid(cn)) || 4587 !_sd_cctl_valid(qp)) 4588 cmn_err(CE_PANIC, 4589 "_sd_centry_alloc %x prev %x next %x qp %x", 4590 cc_ent, cp, cn, qp); 4591 } 4592 #endif 4593 cc_ent->cc_prev->cc_next = cc_ent->cc_next; 4594 cc_ent->cc_next->cc_prev = cc_ent->cc_prev; 4595 cc_ent->cc_next = qhead; 4596 cc_ent->cc_prev = qhead->cc_prev; 4597 qhead->cc_prev->cc_next = cc_ent; 4598 qhead->cc_prev = cc_ent; 4599 cc_ent->cc_seq = q->sq_seq++; 4600 /* was FAST */ 4601 mutex_exit(&q->sq_qlock); 4602 /* 4603 * End inlined requeue. 4604 */ 4605 4606 #if defined(_SD_STATS) 4607 if (_sd_hash_delete(cc_ent, _sd_htable) == 0) 4608 SDTRACE(SDF_REPLACE, 4609 CENTRY_CD(cc_ent), cc_ent->cc_hits, 4610 BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)), 4611 nsc_lbolt(), cc_ent->cc_creat); 4612 cc_ent->cc_creat = nsc_lbolt(); 4613 cc_ent->cc_hits = 0; 4614 #else 4615 #if defined(_SD_DEBUG) 4616 if (_sd_hash_delete(cc_ent, _sd_htable) == 0) { 4617 SDTRACE(SDF_REPLACE|ST_DL, 4618 CENTRY_CD(cc_ent), 4619 cc_ent->cc_valid, 4620 BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)), 4621 cd, BLK_TO_FBA_NUM(cblk)); 4622 if (cc_ent->cc_await_use || 4623 ((cd == CENTRY_CD(cc_ent)) && 4624 (cblk == CENTRY_BLK(cc_ent)))) 4625 DATA_LOG(SDF_REPLACE|ST_DL, cc_ent, 0, 4626 BLK_FBAS); 4627 } 4628 #else 4629 (void) _sd_hash_delete((struct _sd_hash_hd *)cc_ent, 4630 _sd_htable); 4631 #endif 4632 #endif 4633 cc_ent->cc_creat = nsc_lbolt(); 4634 cc_ent->cc_hits = 0; 4635 4636 cc_ent->cc_valid = 0; 4637 categorize_centry = 0; 4638 if (cc_ent->cc_data) 4639 categorize_centry = FOUND_HOLD_OVER_DM; 4640 4641 alloc_try: 4642 if (cd == _CD_NOHASH) 4643 CENTRY_BLK(cc_ent) = cblk; 4644 else if ((old_ent = (_sd_cctl_t *) 4645 _sd_hash_insert(cd, cblk, (struct _sd_hash_hd *)cc_ent, 4646 _sd_htable)) != cc_ent) { 4647 4648 if (SET_CENTRY_INUSE(old_ent)) { 4649 sdbc_centry_inuse++; 4650 4651 if (nowait) { 4652 _sd_centry_release(cc_ent); 4653 cc_ent = NULL; 4654 goto out; 4655 } 4656 4657 if (locked) 4658 rw_exit(&sdbc_queue_lock); 4659 _sd_cc_wait(cd, cblk, old_ent, CC_INUSE); 4660 if (locked) 4661 rw_enter(&sdbc_queue_lock, RW_WRITER); 4662 goto alloc_try; 4663 } 4664 4665 /* 4666 * bug 4529671 4667 * now that we own the centry make sure that 4668 * it is still good. it could have been processed 4669 * by _sd_dealloc_dm() in the window between 4670 * _sd_hash_insert() and SET_CENTRY_INUSE(). 4671 */ 4672 if ((_sd_cctl_t *) 4673 _sd_hash_search(cd, cblk, _sd_htable) != old_ent) { 4674 sdbc_centry_deallocd++; 4675 #ifdef DEBUG 4676 cmn_err(CE_WARN, "!cc_ent %p cd %d cblk %" 4677 NSC_SZFMT " lost to dealloc?! cc_data %p", 4678 (void *)old_ent, cd, cblk, 4679 (void *)old_ent->cc_data); 4680 #endif 4681 4682 CLEAR_CENTRY_INUSE(old_ent); 4683 4684 if (nowait) { 4685 _sd_centry_release(cc_ent); 4686 cc_ent = NULL; 4687 goto out; 4688 } 4689 4690 goto alloc_try; 4691 } 4692 4693 if (CC_CD_BLK_MATCH(cd, cblk, old_ent)) { 4694 sdbc_centry_hit++; 4695 old_ent->cc_toflush = 0; 4696 _sd_centry_release(cc_ent); 4697 cc_ent = old_ent; 4698 categorize_centry = FOUND_IN_HASH_DM; 4699 } else { 4700 sdbc_centry_lost++; 4701 4702 CLEAR_CENTRY_INUSE(old_ent); 4703 4704 if (nowait) { 4705 _sd_centry_release(cc_ent); 4706 cc_ent = NULL; 4707 goto out; 4708 } 4709 4710 goto alloc_try; 4711 } 4712 } 4713 4714 SDTRACE(ST_EXIT|SDF_ENT_ALLOC, cd, tries, 4715 BLK_TO_FBA_NUM(cblk), 0, 0); 4716 4717 if (cc_ent->cc_await_use) { 4718 mutex_enter(&cc_ent->cc_lock); 4719 cv_broadcast(&cc_ent->cc_blkcv); 4720 mutex_exit(&cc_ent->cc_lock); 4721 } 4722 4723 sdbc_centry_init_dm(cc_ent); 4724 4725 cc_ent->cc_aging_dm |= categorize_centry; 4726 4727 out: 4728 return (cc_ent); 4729 } 4730 4731 SDTRACE(ST_INFO|SDF_ENT_ALLOC, cd, ++tries, BLK_TO_FBA_NUM(cblk), 0, 0); 4732 4733 delay(drv_usectohz(20000)); 4734 (void) (*stall)++; 4735 num_tries = _sd_lruq_srch; 4736 goto retry_alloc_centry; 4737 } 4738 4739 /* 4740 * sdbc_centry_init_dm - setup the cache block for dynamic memory allocation 4741 * 4742 * ARGUMENTS: 4743 * centry - Cache block. 4744 * 4745 * RETURNS: 4746 * NONE 4747 * 4748 * USAGE: 4749 * This routine is the central point in which cache entry blocks are setup 4750 */ 4751 static void 4752 sdbc_centry_init_dm(_sd_cctl_t *centry) 4753 { 4754 4755 /* an entry already setup - don't touch simply refresh age */ 4756 if (centry->cc_data) { 4757 centry->cc_aging_dm &= ~(FINAL_AGING_DM); 4758 4759 DTRACE_PROBE1(sdbc_centry_init_dm_end, 4760 char *, centry->cc_data); 4761 return; 4762 } 4763 4764 centry->cc_aging_dm &= ~(FINAL_AGING_DM | CATAGORY_ENTRY_DM); 4765 4766 if (centry->cc_head_dm || centry->cc_next_dm) 4767 cmn_err(cmn_level, "!sdbc(sdbc_centry_init_dm): " 4768 "non-zero mem chain in ccent %p", (void *)centry); 4769 4770 centry->cc_head_dm = 0; 4771 4772 if (!sdbc_use_dmchain) 4773 centry->cc_next_dm = 0; 4774 4775 centry->cc_data = 0; 4776 4777 } 4778 4779 /* 4780 * sdbc_centry_memalloc_dm 4781 * 4782 * Actually allocate the cache memory, storing it in the cc_data field for 4783 * the cctl 4784 * 4785 * ARGS: 4786 * centry: cache control block for which to allocate the memory 4787 * alloc_request: number of bytes to allocate 4788 * flag: if called with ALLOC_NOWAIT, caller must check for non-zero return 4789 * 4790 * RETURNS: 4791 * 0 on success 4792 * non-zero on error 4793 */ 4794 static int 4795 sdbc_centry_memalloc_dm(_sd_cctl_t *centry, int alloc_request, int flag) 4796 { 4797 int cblocks; 4798 _sd_queue_t *newq; 4799 int sleep; 4800 sleep = (flag & ALLOC_NOWAIT) ? KM_NOSLEEP : KM_SLEEP; 4801 4802 if (!centry->cc_data && (alloc_request > 0)) { 4803 /* host or other */ 4804 dynmem_processing_dm.alloc_ct++; 4805 centry->cc_data = (unsigned char *) 4806 kmem_alloc((size_t)centry->cc_alloc_size_dm, sleep); 4807 4808 4809 if (sdbc_use_dmchain) { 4810 cblocks = centry->cc_alloc_size_dm >> _sd_cblock_shift; 4811 newq = &sdbc_dm_queues[cblocks]; 4812 4813 /* set the dmqueue index */ 4814 centry->cc_cblocks = cblocks; 4815 4816 /* put on appropriate queue */ 4817 sdbc_ins_dmqueue_back(newq, centry); 4818 } 4819 4820 /* 4821 * for KM_NOSLEEP (should never happen with KM_SLEEP) 4822 */ 4823 if (!centry->cc_data) 4824 return (LOW_RESOURCES_DM); 4825 centry->cc_head_dm = centry; 4826 centry->cc_alloc_ct_dm++; 4827 } 4828 4829 return (0); 4830 } 4831 4832 /* 4833 * _sd_centry_release - release a cache block 4834 * 4835 * ARGUMENTS: 4836 * centry - Cache block. 4837 * 4838 * RETURNS: 4839 * NONE 4840 * 4841 * USAGE: 4842 * This routine frees up a cache block. It also frees up a write 4843 * block if allocated and its valid to release it. 4844 */ 4845 4846 void 4847 _sd_centry_release(_sd_cctl_t *centry) 4848 { 4849 ss_centry_info_t *wctl; 4850 4851 SDTRACE(ST_ENTER|SDF_ENT_FREE, CENTRY_CD(centry), 0, 4852 BLK_TO_FBA_NUM(CENTRY_BLK(centry)), 0, 0); 4853 4854 CLEAR_CENTRY_PAGEIO(centry); 4855 4856 if ((wctl = centry->cc_write) != 0) { 4857 /* was FAST */ 4858 mutex_enter(¢ry->cc_lock); 4859 if (CENTRY_DIRTY(centry)) 4860 wctl = NULL; 4861 else { 4862 centry->cc_write = NULL; 4863 centry->cc_flag &= ~(CC_PINNABLE); 4864 } 4865 /* was FAST */ 4866 mutex_exit(¢ry->cc_lock); 4867 if (wctl) { 4868 wctl->sc_dirty = 0; 4869 SSOP_SETCENTRY(sdbc_safestore, wctl); 4870 SSOP_DEALLOCRESOURCE(sdbc_safestore, wctl->sc_res); 4871 } 4872 } 4873 4874 if (!(centry->cc_aging_dm & BAD_CHAIN_DM)) { 4875 if (sdbc_use_dmchain) { 4876 if (centry->cc_alloc_size_dm) { 4877 4878 /* see if this can be queued to head */ 4879 if (CENTRY_QHEAD(centry)) { 4880 sdbc_requeue_head_dm_try(centry); 4881 } else { 4882 int qidx; 4883 _sd_queue_t *q; 4884 4885 qidx = centry->cc_cblocks; 4886 q = &sdbc_dm_queues[qidx]; 4887 4888 if (_sd_lru_reinsert(q, centry)) { 4889 sdbc_requeue_dmchain(q, 4890 centry, 1, 1); 4891 } 4892 } 4893 } else { 4894 /* 4895 * Fix for bug 4949134: 4896 * If an internal block is marked with CC_QHEAD 4897 * but the HOST block is not, the chain will 4898 * never age properly, and will never be made 4899 * available. Only the HOST of the dmchain is 4900 * checked for CC_QHEAD, so clearing an internal 4901 * block indiscriminately (as is being done 4902 * here) does no damage. 4903 * 4904 * The same result could instead be achieved by 4905 * not setting the CC_QHEAD flag in the first 4906 * place, if the block is an internal dmchain 4907 * block, and if it is found in the hash table. 4908 * The current solution was chosen since it is 4909 * the least intrusive. 4910 */ 4911 centry->cc_flag &= ~CC_QHEAD; 4912 } 4913 } else { 4914 if (CENTRY_QHEAD(centry)) { 4915 if (!CENTRY_DIRTY(centry)) 4916 _sd_requeue_head(centry); 4917 } else if (_sd_lru_reinsert(_SD_LRU_Q, centry)) 4918 _sd_requeue(centry); 4919 } 4920 } 4921 4922 SDTRACE(ST_EXIT|SDF_ENT_FREE, CENTRY_CD(centry), 0, 4923 BLK_TO_FBA_NUM(CENTRY_BLK(centry)), 0, 0); 4924 4925 /* only clear inuse after final reference to centry */ 4926 4927 CLEAR_CENTRY_INUSE(centry); 4928 } 4929 4930 4931 /* 4932 * lookup to centry info associated with safestore resource 4933 * return pointer to the centry info structure 4934 */ 4935 ss_centry_info_t * 4936 sdbc_get_cinfo_byres(ss_resource_t *res) 4937 { 4938 ss_centry_info_t *cinfo; 4939 ss_centry_info_t *cend; 4940 int found = 0; 4941 4942 ASSERT(res != NULL); 4943 4944 if (res == NULL) 4945 return (NULL); 4946 4947 cinfo = _sdbc_gl_centry_info; 4948 cend = _sdbc_gl_centry_info + 4949 (_sdbc_gl_centry_info_size / sizeof (ss_centry_info_t)) - 1; 4950 4951 for (; cinfo <= cend; ++cinfo) 4952 if (cinfo->sc_res == res) { 4953 ++found; 4954 break; 4955 } 4956 4957 if (!found) 4958 cinfo = NULL; /* bad */ 4959 4960 return (cinfo); 4961 } 4962 4963 /* 4964 * _sd_alloc_write - Allocate a write block (for remote mirroring) 4965 * and set centry->cc_write 4966 * 4967 * ARGUMENTS: 4968 * centry - Head of Cache chain 4969 * stall - pointer to stall count (no blocks avail) 4970 * 4971 * RETURNS: 4972 * 0 - and sets cc_write for all entries when write contl block obtained. 4973 * -1 - if a write control block could not be obtained. 4974 */ 4975 4976 int 4977 _sd_alloc_write(_sd_cctl_t *centry, int *stall) 4978 { 4979 4980 ss_resourcelist_t *reslist; 4981 ss_resourcelist_t *savereslist; 4982 ss_resource_t *res; 4983 _sd_cctl_t *ce; 4984 int err; 4985 int need; 4986 4987 4988 need = 0; 4989 4990 for (ce = centry; ce; ce = ce->cc_chain) { 4991 if (!(ce->cc_write)) 4992 need++; 4993 } 4994 4995 if (!need) 4996 return (0); 4997 4998 if ((SSOP_ALLOCRESOURCE(sdbc_safestore, need, stall, &reslist)) 4999 == SS_OK) { 5000 savereslist = reslist; 5001 for (ce = centry; ce; ce = ce->cc_chain) { 5002 if (ce->cc_write) 5003 continue; 5004 err = SSOP_GETRESOURCE(sdbc_safestore, &reslist, &res); 5005 if (err == SS_OK) 5006 ce->cc_write = sdbc_get_cinfo_byres(res); 5007 5008 ASSERT(err == SS_OK); /* panic if DEBUG on */ 5009 ASSERT(ce->cc_write != NULL); 5010 5011 /* 5012 * this is bad and should not happen. 5013 * we use the saved reslist to cleanup 5014 * and return. 5015 */ 5016 if ((err != SS_OK) || !ce->cc_write) { 5017 5018 cmn_err(CE_WARN, "!_sd_alloc_write: " 5019 "bad resource list 0x%p" 5020 "changing to forced write thru mode", 5021 (void *)savereslist); 5022 5023 (void) _sd_set_node_hint(NSC_FORCED_WRTHRU); 5024 5025 while (SSOP_GETRESOURCE(sdbc_safestore, 5026 &savereslist, &res) == SS_OK) { 5027 5028 SSOP_DEALLOCRESOURCE(sdbc_safestore, 5029 res); 5030 } 5031 5032 return (-1); 5033 5034 } 5035 5036 } 5037 return (0); 5038 } 5039 5040 /* no safestore resources available. do sync write */ 5041 _sd_unblock(&_sd_flush_cv); 5042 return (-1); 5043 } 5044 5045 /* 5046 * _sd_read - Interface call to do read. 5047 * 5048 * ARGUMENTS: 5049 * handle - handle allocated earlier on. 5050 * fba_pos - disk block number to read from. 5051 * fba_len - length in fbas. 5052 * flag - flag: (NSC_NOBLOCK for async io) 5053 * 5054 * RETURNS: 5055 * errno if return > 0 5056 * NSC_DONE or NSC_PENDING otherwise. 5057 * 5058 * USAGE: 5059 * This routine checks if the request is valid and calls the underlying 5060 * doread routine (also called by alloc_buf) 5061 */ 5062 5063 int 5064 _sd_read(_sd_buf_handle_t *handle, nsc_off_t fba_pos, nsc_size_t fba_len, 5065 int flag) 5066 { 5067 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 5068 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 5069 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 5070 _sd_cctl_t *cc_ent = NULL; 5071 nsc_size_t fba_orig_len = fba_len; 5072 int ret; 5073 int cd = HANDLE_CD(handle); 5074 5075 if (_sdbc_shutdown_in_progress || (handle->bh_flag & NSC_ABUF)) { 5076 ret = EIO; 5077 goto out; 5078 } 5079 5080 5081 #if !defined(_SD_NOCHECKS) 5082 if (!_SD_HANDLE_ACTIVE(handle)) { 5083 cmn_err(CE_WARN, "!sdbc(_sd_read) handle %p not active", 5084 (void *)handle); 5085 ret = EINVAL; 5086 goto out; 5087 } 5088 ASSERT_HANDLE_LIMITS(handle, fba_pos, fba_len); 5089 #endif 5090 if (fba_len == 0) { 5091 ret = NSC_DONE; 5092 goto out; 5093 } 5094 5095 KSTAT_RUNQ_ENTER(cd); 5096 5097 st_cblk_off = BLK_FBA_OFF(fba_pos); 5098 st_cblk_len = BLK_FBAS - st_cblk_off; 5099 if ((nsc_size_t)st_cblk_len >= fba_len) { 5100 end_cblk_len = 0; 5101 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 5102 } else { 5103 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 5104 } 5105 5106 cc_ent = handle->bh_centry; 5107 while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos)) 5108 cc_ent = cc_ent->cc_chain; 5109 5110 if (!SDBC_VALID_BITS(st_cblk_off, st_cblk_len, cc_ent)) 5111 goto need_io; 5112 DATA_LOG(SDF_RD, cc_ent, st_cblk_off, st_cblk_len); 5113 5114 DTRACE_PROBE4(_sd_read_data1, uint64_t, 5115 (uint64_t)(BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)) + st_cblk_off), 5116 uint64_t, (uint64_t)st_cblk_len, char *, 5117 *(int64_t *)(cc_ent->cc_data + FBA_SIZE(st_cblk_off)), 5118 char *, *(int64_t *)(cc_ent->cc_data + 5119 FBA_SIZE(st_cblk_off + st_cblk_len) - 8)); 5120 5121 fba_pos += st_cblk_len; 5122 fba_len -= st_cblk_len; 5123 cc_ent = cc_ent->cc_chain; 5124 5125 while (fba_len > (nsc_size_t)end_cblk_len) { 5126 if (!FULLY_VALID(cc_ent)) 5127 goto need_io; 5128 DATA_LOG(SDF_RD, cc_ent, 0, BLK_FBAS); 5129 5130 DTRACE_PROBE4(_sd_read_data2, uint64_t, 5131 (uint64_t)BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)), 5132 uint64_t, (uint64_t)BLK_FBAS, 5133 char *, *(int64_t *)(cc_ent->cc_data), 5134 char *, *(int64_t *)(cc_ent->cc_data + 5135 FBA_SIZE(BLK_FBAS) - 8)); 5136 5137 fba_pos += BLK_FBAS; 5138 fba_len -= BLK_FBAS; 5139 cc_ent = cc_ent->cc_chain; 5140 } 5141 if (fba_len) { 5142 if (!SDBC_VALID_BITS(0, end_cblk_len, cc_ent)) 5143 goto need_io; 5144 DATA_LOG(SDF_RD, cc_ent, 0, end_cblk_len); 5145 5146 DTRACE_PROBE4(_sd_read_data3, uint64_t, 5147 (uint64_t)BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)), 5148 uint64_t, (uint64_t)end_cblk_len, 5149 char *, *(int64_t *)(cc_ent->cc_data), 5150 char *, *(int64_t *)(cc_ent->cc_data + 5151 FBA_SIZE(end_cblk_len) - 8)); 5152 } 5153 5154 CACHE_FBA_READ(handle->bh_cd, fba_orig_len); 5155 CACHE_READ_HIT; 5156 5157 FBA_READ_IO_KSTATS(handle->bh_cd, FBA_SIZE(fba_orig_len)); 5158 5159 ret = NSC_HIT; 5160 goto stats_exit; 5161 need_io: 5162 _SD_DISCONNECT_CALLBACK(handle); 5163 5164 ret = _sd_doread(handle, cc_ent, fba_pos, fba_len, flag); 5165 5166 stats_exit: 5167 KSTAT_RUNQ_EXIT(cd); 5168 out: 5169 return (ret); 5170 } 5171 5172 5173 /* 5174 * sdbc_doread_prefetch - read ahead one cache block 5175 * 5176 * ARGUMENTS: 5177 * cc_ent - cache entry 5178 * fba_pos - disk block number to read from 5179 * fba_len - length in fbas. 5180 * 5181 * RETURNS: 5182 * number of fbas, if any, that are to be read beyond (fba_pos + fba_len) 5183 * 5184 * USAGE: 5185 * if readahead is to be done allocate a cache block and place 5186 * on the cc_chain of cc_ent 5187 */ 5188 static int 5189 sdbc_doread_prefetch(_sd_cctl_t *cc_ent, nsc_off_t fba_pos, nsc_size_t fba_len) 5190 { 5191 nsc_off_t st_cblk = FBA_TO_BLK_NUM(fba_pos); 5192 nsc_off_t next_cblk = FBA_TO_BLK_NUM(fba_pos + BLK_FBAS); 5193 nsc_size_t filesize; 5194 int fba_count = 0; /* number of fbas to prefetch */ 5195 _sd_cctl_t *cc_ra; /* the read ahead cache entry */ 5196 int cd = CENTRY_CD(cc_ent); 5197 nsc_size_t vol_fill; 5198 5199 filesize = _sd_cache_files[cd].cd_info->sh_filesize; 5200 vol_fill = filesize - (fba_pos + fba_len); 5201 5202 /* readahead only for small reads */ 5203 if ((fba_len <= FBA_LEN(CACHE_BLOCK_SIZE)) && (fba_pos != 0) && 5204 (vol_fill > 0)) { 5205 5206 /* 5207 * if prev block is in cache and next block is not, 5208 * then read ahead one block 5209 */ 5210 if (_sd_hash_search(cd, st_cblk - 1, _sd_htable)) { 5211 if (!_sd_hash_search(cd, next_cblk, _sd_htable)) { 5212 5213 cc_ra = sdbc_centry_alloc_blks 5214 (cd, next_cblk, 1, ALLOC_NOWAIT); 5215 if (cc_ra) { 5216 /* if in cache don't readahead */ 5217 if (cc_ra->cc_aging_dm & 5218 HASH_ENTRY_DM) { 5219 ++sdbc_ra_hash; 5220 _sd_centry_release(cc_ra); 5221 } else { 5222 cc_ent->cc_chain = cc_ra; 5223 cc_ra->cc_chain = 0; 5224 fba_count = 5225 (vol_fill > 5226 (nsc_size_t)BLK_FBAS) ? 5227 BLK_FBAS : (int)vol_fill; 5228 /* 5229 * indicate implicit prefetch 5230 * and mark for release in 5231 * _sd_read_complete() 5232 */ 5233 cc_ra->cc_aging_dm |= 5234 (PREFETCH_BUF_I | 5235 PREFETCH_BUF_IR); 5236 } 5237 } else { 5238 ++sdbc_ra_none; 5239 } 5240 } 5241 } 5242 5243 } 5244 5245 return (fba_count); 5246 } 5247 5248 /* 5249 * _sd_doread - Check if blocks in cache. If not completely true, do io. 5250 * 5251 * ARGUMENTS: 5252 * handle - handle allocated earlier on. 5253 * fba_pos - disk block number to read from. 5254 * fba_len - length in fbas. 5255 * flag - flag: (NSC_NOBLOCK for async io) 5256 * 5257 * RETURNS: 5258 * errno if return > 0 5259 * NSC_DONE(from disk), or NSC_PENDING otherwise. 5260 * 5261 * Comments: 5262 * It initiates an io and either blocks waiting for the completion 5263 * or return NSC_PENDING, depending on whether the flag bit 5264 * NSC_NOBLOCK is reset or set. 5265 * 5266 */ 5267 5268 5269 static int 5270 _sd_doread(_sd_buf_handle_t *handle, _sd_cctl_t *cc_ent, nsc_off_t fba_pos, 5271 nsc_size_t fba_len, int flag) 5272 { 5273 int cd, err; 5274 nsc_size_t fba_orig_len; /* length in FBA's of the original request */ 5275 nsc_size_t file_len; /* length in bytes of io to be done */ 5276 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 5277 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 5278 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 5279 int num_bdl; 5280 _sd_cctl_t *cc_temp; 5281 struct buf *bp; 5282 unsigned int want_bits; 5283 void (*fn)(blind_t, nsc_off_t, nsc_size_t, int); 5284 sdbc_cblk_fba_t end_cblk_fill; /* FBA's to fill to end of last block */ 5285 nsc_size_t vol_end_fill; /* # of FBA's to fill to end of the volume */ 5286 5287 cd = HANDLE_CD(handle); 5288 SDTRACE(ST_ENTER|SDF_READ, cd, fba_len, fba_pos, flag, 0); 5289 5290 ASSERT(cd >= 0); 5291 if (_sd_cache_files[cd].cd_info->sh_failed) { 5292 SDTRACE(ST_EXIT|SDF_READ, cd, fba_len, fba_pos, flag, EIO); 5293 return (EIO); 5294 } 5295 5296 /* 5297 * adjust the position and length so that the entire cache 5298 * block is read in 5299 */ 5300 5301 /* first, adjust to beginning of cache block */ 5302 5303 fba_len += BLK_FBA_OFF(fba_pos); /* add start offset to length */ 5304 fba_pos &= ~BLK_FBA_MASK; /* move position back to start of block */ 5305 5306 /* compute fill to end of cache block */ 5307 end_cblk_fill = (BLK_FBAS - 1) - ((fba_len - 1) % BLK_FBAS); 5308 vol_end_fill = _sd_cache_files[(cd)].cd_info->sh_filesize - 5309 (fba_pos + fba_len); 5310 5311 /* fill to lesser of cache block or end of volume */ 5312 fba_len += ((nsc_size_t)end_cblk_fill < vol_end_fill) ? end_cblk_fill : 5313 vol_end_fill; 5314 5315 DTRACE_PROBE2(_sd_doread_rfill, nsc_off_t, fba_pos, 5316 nsc_size_t, fba_len); 5317 5318 5319 /* for small reads do 1-block readahead if previous block is in cache */ 5320 if (sdbc_prefetch1) 5321 fba_len += sdbc_doread_prefetch(cc_ent, fba_pos, fba_len); 5322 5323 fba_orig_len = fba_len; 5324 st_cblk_off = BLK_FBA_OFF(fba_pos); 5325 st_cblk_len = BLK_FBAS - st_cblk_off; 5326 if ((nsc_size_t)st_cblk_len >= fba_len) { 5327 end_cblk_len = 0; 5328 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 5329 } else { 5330 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 5331 } 5332 5333 cc_temp = cc_ent; 5334 num_bdl = 0; 5335 while (cc_temp) { 5336 num_bdl += (SDBC_LOOKUP_IOCOUNT(CENTRY_DIRTY(cc_temp))); 5337 cc_temp = cc_temp->cc_chain; 5338 } 5339 bp = sd_alloc_iob(_sd_cache_files[cd].cd_crdev, 5340 fba_pos, num_bdl, B_READ); 5341 if (bp == NULL) { 5342 SDTRACE(ST_EXIT|SDF_READ, cd, fba_len, fba_pos, flag, E2BIG); 5343 return (E2BIG); 5344 } 5345 5346 want_bits = SDBC_GET_BITS(st_cblk_off, st_cblk_len); 5347 if (want_bits & CENTRY_DIRTY(cc_ent)) 5348 _sd_ccent_rd(cc_ent, want_bits, bp); 5349 else { 5350 sd_add_fba(bp, &cc_ent->cc_addr, st_cblk_off, st_cblk_len); 5351 } 5352 file_len = FBA_SIZE(st_cblk_len); 5353 cc_ent = cc_ent->cc_chain; 5354 fba_len -= st_cblk_len; 5355 5356 while (fba_len > (nsc_size_t)end_cblk_len) { 5357 if (CENTRY_DIRTY(cc_ent)) 5358 _sd_ccent_rd(cc_ent, (uint_t)BLK_FBA_BITS, bp); 5359 else { 5360 sd_add_fba(bp, &cc_ent->cc_addr, 0, BLK_FBAS); 5361 } 5362 file_len += CACHE_BLOCK_SIZE; 5363 cc_ent = cc_ent->cc_chain; 5364 fba_len -= BLK_FBAS; 5365 } 5366 5367 if (fba_len) { 5368 want_bits = SDBC_GET_BITS(0, end_cblk_len); 5369 if (want_bits & CENTRY_DIRTY(cc_ent)) 5370 _sd_ccent_rd(cc_ent, want_bits, bp); 5371 else { 5372 sd_add_fba(bp, &cc_ent->cc_addr, 0, end_cblk_len); 5373 } 5374 file_len += FBA_SIZE(end_cblk_len); 5375 } 5376 5377 CACHE_READ_MISS; 5378 FBA_READ_IO_KSTATS(cd, file_len); 5379 5380 DISK_FBA_READ(cd, FBA_NUM(file_len)); 5381 5382 fn = (handle->bh_flag & NSC_NOBLOCK) ? _sd_async_read_ea : NULL; 5383 err = sd_start_io(bp, _sd_cache_files[cd].cd_strategy, fn, handle); 5384 5385 if (err != NSC_PENDING) { 5386 _sd_read_complete(handle, fba_pos, fba_orig_len, err); 5387 } 5388 5389 SDTRACE(ST_EXIT|SDF_READ, cd, fba_orig_len, fba_pos, flag, err); 5390 5391 return (err); 5392 } 5393 5394 5395 5396 /* 5397 * _sd_read_complete - Do whatever is necessary after a read io is done. 5398 * 5399 * ARGUMENTS: 5400 * handle - handle allocated earlier on. 5401 * fba_pos - disk block number to read from. 5402 * fba_len - length in fbas. 5403 * error - error from io if any. 5404 * 5405 * RETURNS: 5406 * NONE. 5407 * 5408 * Comments: 5409 * This routine marks the cache blocks valid if the io completed 5410 * sucessfully. Called from the async end action as well as after 5411 * a synchrnous read completes. 5412 */ 5413 5414 void 5415 _sd_read_complete(_sd_buf_handle_t *handle, nsc_off_t fba_pos, 5416 nsc_size_t fba_len, int error) 5417 { 5418 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 5419 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 5420 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 5421 nsc_size_t cur_fba_len; /* length in FBA's */ 5422 _sd_cctl_t *cc_iocent; 5423 _sd_cctl_t *first_iocent; /* first buffer when processing prefetch */ 5424 5425 cc_iocent = handle->bh_centry; 5426 5427 if ((handle->bh_error = error) == 0) { 5428 while (CENTRY_BLK(cc_iocent) != FBA_TO_BLK_NUM(fba_pos)) 5429 cc_iocent = cc_iocent->cc_chain; 5430 5431 cur_fba_len = fba_len; 5432 st_cblk_off = BLK_FBA_OFF(fba_pos); 5433 st_cblk_len = BLK_FBAS - st_cblk_off; 5434 if ((nsc_size_t)st_cblk_len >= fba_len) { 5435 end_cblk_len = 0; 5436 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 5437 } else { 5438 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 5439 } 5440 5441 SDBC_SET_VALID_BITS(st_cblk_off, st_cblk_len, cc_iocent); 5442 DATA_LOG(SDF_RDIO, cc_iocent, st_cblk_off, st_cblk_len); 5443 5444 DTRACE_PROBE4(_sd_read_complete_data1, uint64_t, (uint64_t) 5445 BLK_TO_FBA_NUM(CENTRY_BLK(cc_iocent)) + st_cblk_off, 5446 int, st_cblk_len, char *, 5447 *(int64_t *)(cc_iocent->cc_data + FBA_SIZE(st_cblk_off)), 5448 char *, *(int64_t *)(cc_iocent->cc_data + 5449 FBA_SIZE(st_cblk_off + st_cblk_len) - 8)); 5450 5451 5452 first_iocent = cc_iocent; 5453 cc_iocent = cc_iocent->cc_chain; 5454 cur_fba_len -= st_cblk_len; 5455 5456 while (cur_fba_len > (nsc_size_t)end_cblk_len) { 5457 SET_FULLY_VALID(cc_iocent); 5458 DATA_LOG(SDF_RDIO, cc_iocent, 0, BLK_FBAS); 5459 5460 DTRACE_PROBE4(_sd_read_complete_data2, uint64_t, 5461 (uint64_t)BLK_TO_FBA_NUM(CENTRY_BLK(cc_iocent)), 5462 int, BLK_FBAS, char *, 5463 *(int64_t *)(cc_iocent->cc_data), char *, 5464 *(int64_t *)(cc_iocent->cc_data + 5465 FBA_SIZE(BLK_FBAS) - 8)); 5466 5467 /* 5468 * 4755485 release implicit prefetch buffers 5469 * 5470 * the cc_chain of the first buffer must NULL'd 5471 * else _sd_free_buf() will do a double free when 5472 * it traverses the chain. 5473 * 5474 * if a buffer has been marked PREFETCH_BUF_IR then 5475 * it is guaranteed that 5476 * 1. it is the second in a chain of two. 5477 * 2. cur_fba_len is BLK_FBAS. 5478 * 3. end_cblk_len is zero. 5479 * 5480 * because of 1 (and 2) above, we can safely exit the 5481 * while loop via the break statement without 5482 * executing the last two statements. the break 5483 * statement is necessary because it would be unsafe 5484 * to access cc_iocent which could be reallocated 5485 * immediately after the _sd_centry_release(). 5486 */ 5487 if (cc_iocent->cc_aging_dm & PREFETCH_BUF_IR) { 5488 cc_iocent->cc_aging_dm &= ~(PREFETCH_BUF_IR); 5489 _sd_centry_release(cc_iocent); 5490 first_iocent->cc_chain = NULL; 5491 break; 5492 } 5493 5494 cc_iocent = cc_iocent->cc_chain; 5495 cur_fba_len -= BLK_FBAS; 5496 } 5497 if (end_cblk_len) { 5498 SDBC_SET_VALID_BITS(0, end_cblk_len, cc_iocent); 5499 DATA_LOG(SDF_RDIO, cc_iocent, 0, end_cblk_len); 5500 5501 DTRACE_PROBE4(_sd_read_complete_data3, uint64_t, 5502 (uint64_t)BLK_TO_FBA_NUM(CENTRY_BLK(cc_iocent)), 5503 int, end_cblk_len, char *, 5504 *(int64_t *)(cc_iocent->cc_data), char *, 5505 *(int64_t *)(cc_iocent->cc_data + 5506 FBA_SIZE(end_cblk_len) - 8)); 5507 } 5508 } 5509 5510 } 5511 5512 5513 /* 5514 * _sd_async_read_ea - End action for async reads. 5515 * 5516 * ARGUMENTS: 5517 * xhandle - handle allocated earlier on (cast to blind_t). 5518 * fba_pos - disk block number read from. 5519 * fba_len - length in fbas. 5520 * error - error from io if any. 5521 * 5522 * RETURNS: 5523 * NONE. 5524 * 5525 * Comments: 5526 * This routine is called at interrupt level when the io is done. 5527 * This is called only when read is asynchronous (NSC_NOBLOCK) 5528 */ 5529 5530 static void 5531 _sd_async_read_ea(blind_t xhandle, nsc_off_t fba_pos, nsc_size_t fba_len, 5532 int error) 5533 { 5534 _sd_buf_handle_t *handle = xhandle; 5535 int cd; 5536 5537 if (error) { 5538 cd = HANDLE_CD(handle); 5539 ASSERT(cd >= 0); 5540 _sd_cache_files[cd].cd_info->sh_failed = 1; 5541 } 5542 SDTRACE(ST_ENTER|SDF_READ_EA, HANDLE_CD(handle), 5543 handle->bh_fba_len, handle->bh_fba_pos, 0, error); 5544 5545 _sd_read_complete(handle, fba_pos, fba_len, error); 5546 5547 #if defined(_SD_DEBUG_PATTERN) 5548 check_buf_consistency(handle, "rd"); 5549 #endif 5550 5551 SDTRACE(ST_EXIT|SDF_READ_EA, HANDLE_CD(handle), 5552 handle->bh_fba_len, handle->bh_fba_pos, 0, 0); 5553 _SD_READ_CALLBACK(handle); 5554 } 5555 5556 5557 /* 5558 * _sd_async_write_ea - End action for async writes. 5559 * 5560 * ARGUMENTS: 5561 * xhandle - handle allocated earlier on. (cast to blind_t) 5562 * fba_pos - disk block number written to. 5563 * fba_len - length in fbas. 5564 * error - error from io if any. 5565 * 5566 * RETURNS: 5567 * NONE. 5568 * 5569 * Comments: 5570 * This routine is called at interrupt level when the write io is done. 5571 * This is called only when we are in write-through mode and the write 5572 * call indicated asynchronous callback. (NSC_NOBLOCK) 5573 */ 5574 5575 /* ARGSUSED */ 5576 5577 static void 5578 _sd_async_write_ea(blind_t xhandle, nsc_off_t fba_pos, nsc_size_t fba_len, 5579 int error) 5580 { 5581 _sd_buf_handle_t *handle = xhandle; 5582 handle->bh_error = error; 5583 5584 if (error) 5585 _sd_cache_files[HANDLE_CD(handle)].cd_info->sh_failed = 1; 5586 5587 _SD_WRITE_CALLBACK(handle); 5588 } 5589 5590 /* 5591 * update_dirty - set dirty bits in cache block which is already dirty 5592 * cc_inuse is held, need cc_lock to avoid race with _sd_process_pending 5593 * must check for I/O in-progress and set PEND_DIRTY. 5594 * return previous dirty bits 5595 * [if set _sd_process_pending will re-issue] 5596 */ 5597 static _sd_bitmap_t 5598 update_dirty(_sd_cctl_t *cc_ent, sdbc_cblk_fba_t st_off, sdbc_cblk_fba_t st_len) 5599 { 5600 _sd_bitmap_t old; 5601 5602 /* was FAST */ 5603 mutex_enter(&cc_ent->cc_lock); 5604 old = CENTRY_DIRTY(cc_ent); 5605 if (old) { 5606 /* 5607 * If we are writing to an FBA that is still marked dirty, 5608 * record a write cancellation. 5609 */ 5610 if (old & SDBC_GET_BITS(st_off, st_len)) { 5611 CACHE_WRITE_CANCELLATION(CENTRY_CD(cc_ent)); 5612 } 5613 5614 /* This is a write to a block that was already dirty */ 5615 SDBC_SET_DIRTY(st_off, st_len, cc_ent); 5616 sd_serialize(); 5617 if (CENTRY_IO_INPROGRESS(cc_ent)) 5618 cc_ent->cc_flag |= CC_PEND_DIRTY; 5619 } 5620 /* was FAST */ 5621 mutex_exit(&cc_ent->cc_lock); 5622 return (old); 5623 } 5624 5625 /* 5626 * _sd_write - Interface call to commit part of handle. 5627 * 5628 * ARGUMENTS: 5629 * handle - handle allocated earlier o. 5630 * fba_pos - disk block number to write to. 5631 * fba_len - length in fbas. 5632 * flag - (NSC_NOBLOCK | NSC_WRTHRU) 5633 * 5634 * RETURNS: 5635 * errno if return > 0 5636 * NSC_HIT (in cache), NSC_DONE (to disk) or NSC_PENDING otherwise. 5637 * 5638 * Comments: 5639 * This routine checks validity of the handle and then calls the 5640 * sync-write function if this write is determined to be write-through. 5641 * Else, it reflects the data to the write blocks on the mirror node, 5642 * (allocated in alloc_buf). If the cache block is not dirty, it is 5643 * marked dirty and queued up for io processing later on. 5644 * If parts are already dirty but io is not in progress yet, it is 5645 * marked dirty and left alone (it is already in the queue) 5646 * If parts are already dirty but io is in progress, it is marked 5647 * dirty and also a flag is set indicating that this buffer should 5648 * be reprocessed after the io-end-action. 5649 * Attempt is made to coalesce multiple writes into a single list 5650 * for io processing later on. 5651 * 5652 * Issuing of writes may be delayed until the handle is released; 5653 * _sd_queue_write() sets NSC_QUEUE, indicating that dirty bits 5654 * and reflection to mirror have already been done, just queue I/O. 5655 */ 5656 5657 5658 5659 int 5660 _sd_write(_sd_buf_handle_t *handle, nsc_off_t fba_pos, nsc_size_t fba_len, 5661 int flag) 5662 { 5663 int cd = HANDLE_CD(handle); 5664 int num_queued, ret, queue_only, store_only; 5665 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 5666 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 5667 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 5668 nsc_size_t cur_fba_len; /* position in disk blocks */ 5669 _sd_cctl_t *cc_ent = NULL; 5670 _sd_cctl_t *cur_chain = NULL, *dirty_next = NULL; 5671 5672 5673 if (_sdbc_shutdown_in_progress) { 5674 ret = EIO; 5675 goto out; 5676 } 5677 5678 5679 if (!_SD_HANDLE_ACTIVE(handle)) { 5680 SDALERT(SDF_WRITE, 5681 SDT_INV_CD, 0, SDT_INV_BL, handle->bh_flag, 0); 5682 ret = EINVAL; 5683 goto out; 5684 } 5685 #if !defined(_SD_NOCHECKS) 5686 ASSERT_HANDLE_LIMITS(handle, fba_pos, fba_len); 5687 if ((handle->bh_flag & NSC_WRBUF) == 0) { 5688 ret = EINVAL; 5689 goto out; 5690 } 5691 #endif 5692 if (fba_len == 0) { 5693 ret = NSC_DONE; 5694 goto out; 5695 } 5696 5697 /* 5698 * store_only: don't queue this I/O yet 5699 * queue_only: queue I/O to disk, don't store in mirror node 5700 */ 5701 if (flag & NSC_QUEUE) 5702 queue_only = 1, store_only = 0; 5703 else 5704 if (_SD_DELAY_QUEUE && (fba_len != handle->bh_fba_len)) 5705 queue_only = 0, store_only = 1; 5706 else 5707 queue_only = store_only = 0; 5708 5709 if (!queue_only && _SD_FORCE_DISCONNECT(fba_len)) 5710 _SD_DISCONNECT_CALLBACK(handle); 5711 5712 if (_sd_cache_files[cd].cd_info->sh_failed) { 5713 ret = EIO; 5714 goto out; 5715 } 5716 5717 KSTAT_RUNQ_ENTER(cd); 5718 5719 SDTRACE(ST_ENTER|SDF_WRITE, cd, fba_len, fba_pos, flag, 0); 5720 5721 #if defined(_SD_DEBUG_PATTERN) 5722 check_buf_consistency(handle, "wr"); 5723 #endif 5724 5725 cc_ent = handle->bh_centry; 5726 5727 while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos)) 5728 cc_ent = cc_ent->cc_chain; 5729 5730 if (((handle->bh_flag | flag) & _SD_WRTHRU_MASK) || 5731 (!queue_only && _sd_remote_store(cc_ent, fba_pos, fba_len))) { 5732 flag |= NSC_WRTHRU; 5733 5734 ret = _sd_sync_write(handle, fba_pos, fba_len, flag); 5735 goto stats_exit; 5736 } 5737 5738 if (store_only) /* enqueue in _sd_free_buf() */ 5739 handle->bh_flag |= NSC_QUEUE; 5740 cur_fba_len = fba_len; 5741 st_cblk_off = BLK_FBA_OFF(fba_pos); 5742 st_cblk_len = BLK_FBAS - st_cblk_off; 5743 if ((nsc_size_t)st_cblk_len >= fba_len) { 5744 end_cblk_len = 0; 5745 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 5746 } else { 5747 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 5748 } 5749 5750 if (CENTRY_DIRTY(cc_ent) && update_dirty(cc_ent, st_cblk_off, 5751 st_cblk_len)) 5752 goto loop1; 5753 if (store_only) { 5754 SDBC_SET_TOFLUSH(st_cblk_off, st_cblk_len, cc_ent); 5755 goto loop1; 5756 } 5757 SDBC_SET_DIRTY(st_cblk_off, st_cblk_len, cc_ent); 5758 cur_chain = dirty_next = cc_ent; 5759 num_queued = 1; 5760 5761 loop1: 5762 DATA_LOG(SDF_WR, cc_ent, st_cblk_off, st_cblk_len); 5763 5764 DTRACE_PROBE4(_sd_write_data1, uint64_t, (uint64_t) 5765 (BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)) + st_cblk_off), 5766 int, st_cblk_len, char *, 5767 *(int64_t *)(cc_ent->cc_data + FBA_SIZE(st_cblk_off)), 5768 char *, *(int64_t *)(cc_ent->cc_data + 5769 FBA_SIZE(st_cblk_off+ st_cblk_len) - 8)); 5770 5771 cur_fba_len -= st_cblk_len; 5772 cc_ent = cc_ent->cc_chain; 5773 5774 while (cur_fba_len > (nsc_size_t)end_cblk_len) { 5775 if (CENTRY_DIRTY(cc_ent) && update_dirty(cc_ent, 0, BLK_FBAS)) { 5776 if (cur_chain) { 5777 _sd_enqueue_dirty(cd, cur_chain, dirty_next, 5778 num_queued); 5779 cur_chain = dirty_next = NULL; 5780 } 5781 goto loop2; 5782 } 5783 if (store_only) { 5784 SDBC_SET_TOFLUSH(0, BLK_FBAS, cc_ent); 5785 goto loop2; 5786 } 5787 SDBC_SET_DIRTY(0, BLK_FBAS, cc_ent); 5788 if (dirty_next) { 5789 dirty_next->cc_dirty_next = cc_ent; 5790 dirty_next = cc_ent; 5791 num_queued++; 5792 } else { 5793 cur_chain = dirty_next = cc_ent; 5794 num_queued = 1; 5795 } 5796 loop2: 5797 DATA_LOG(SDF_WR, cc_ent, 0, BLK_FBAS); 5798 5799 DTRACE_PROBE4(_sd_write_data2, uint64_t, 5800 (uint64_t)(BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent))), 5801 int, BLK_FBAS, char *, *(int64_t *)(cc_ent->cc_data), 5802 char *, *(int64_t *)(cc_ent->cc_data + 5803 FBA_SIZE(BLK_FBAS) - 8)); 5804 5805 cc_ent = cc_ent->cc_chain; 5806 cur_fba_len -= BLK_FBAS; 5807 } 5808 5809 #if defined(_SD_DEBUG) 5810 if (cur_fba_len != end_cblk_len) 5811 cmn_err(CE_WARN, "!fba_len %" NSC_SZFMT " end_cblk_len %d in " 5812 "_sd_write", cur_fba_len, end_cblk_len); 5813 #endif 5814 5815 if (cur_fba_len) { 5816 if (CENTRY_DIRTY(cc_ent) && update_dirty(cc_ent, 0, 5817 end_cblk_len)) { 5818 if (cur_chain) { 5819 _sd_enqueue_dirty(cd, cur_chain, dirty_next, 5820 num_queued); 5821 cur_chain = dirty_next = NULL; 5822 } 5823 goto loop3; 5824 } 5825 if (store_only) { 5826 SDBC_SET_TOFLUSH(0, end_cblk_len, cc_ent); 5827 goto loop3; 5828 } 5829 SDBC_SET_DIRTY(0, end_cblk_len, cc_ent); 5830 if (dirty_next) { 5831 dirty_next->cc_dirty_next = cc_ent; 5832 dirty_next = cc_ent; 5833 num_queued++; 5834 } else { 5835 cur_chain = dirty_next = cc_ent; 5836 num_queued = 1; 5837 } 5838 } 5839 loop3: 5840 if (cur_fba_len) { 5841 DATA_LOG(SDF_WR, cc_ent, 0, end_cblk_len); 5842 5843 DTRACE_PROBE4(_sd_write_data3, uint64_t, 5844 (uint64_t)(BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent))), 5845 int, end_cblk_len, char *, *(int64_t *)(cc_ent->cc_data), 5846 char *, *(int64_t *)(cc_ent->cc_data + 5847 FBA_SIZE(end_cblk_len) - 8)); 5848 5849 } 5850 5851 if (!store_only && cur_chain) { 5852 _sd_enqueue_dirty(cd, cur_chain, dirty_next, num_queued); 5853 } 5854 5855 if (!queue_only) { 5856 CACHE_FBA_WRITE(cd, fba_len); 5857 CACHE_WRITE_HIT; 5858 5859 FBA_WRITE_IO_KSTATS(cd, FBA_SIZE(fba_len)); 5860 } 5861 5862 ret = NSC_HIT; 5863 5864 stats_exit: 5865 SDTRACE(ST_EXIT|SDF_WRITE, cd, fba_len, fba_pos, flag, ret); 5866 KSTAT_RUNQ_EXIT(cd); 5867 out: 5868 return (ret); 5869 } 5870 5871 5872 /* 5873 * _sd_queue_write(handle, fba_pos, fba_len): Queues delayed writes for 5874 * flushing 5875 * 5876 * ARGUMENTS: handle - handle allocated with NSC_WRBUF 5877 * fba_pos - starting fba pos from _sd_alloc_buf() 5878 * fba_len - fba len from _sd_alloc_buf() 5879 * 5880 * USAGE : Called if _SD_DELAY_QUEUE is set. Finds all blocks in the 5881 * handle marked for flushing and queues them to be written in 5882 * optimized (i.e. sequential) order 5883 */ 5884 static void 5885 _sd_queue_write(_sd_buf_handle_t *handle, nsc_off_t fba_pos, nsc_size_t fba_len) 5886 { 5887 nsc_off_t fba_end; 5888 sdbc_cblk_fba_t sblk, len, dirty; 5889 _sd_cctl_t *cc_ent; 5890 nsc_off_t flush_pos; 5891 int flush_pos_valid = 0; 5892 nsc_size_t flush_len = 0; 5893 5894 cc_ent = handle->bh_centry; 5895 fba_end = fba_pos + fba_len; 5896 fba_pos = BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)); /* 1st block */ 5897 while (fba_pos < fba_end) { 5898 dirty = cc_ent->cc_toflush; 5899 cc_ent->cc_toflush = 0; 5900 /* 5901 * Full block 5902 */ 5903 if (_SD_BMAP_ISFULL(dirty)) { 5904 if (flush_pos_valid == 0) { 5905 flush_pos_valid = 1; 5906 flush_pos = fba_pos; 5907 } 5908 flush_len += BLK_FBAS; 5909 } 5910 /* 5911 * Partial block 5912 */ 5913 else while (dirty) { 5914 sblk = SDBC_LOOKUP_STPOS(dirty); 5915 len = SDBC_LOOKUP_LEN(dirty); 5916 SDBC_LOOKUP_MODIFY(dirty); 5917 5918 if (sblk && flush_pos_valid) { 5919 (void) _sd_write(handle, flush_pos, flush_len, 5920 NSC_QUEUE); 5921 flush_pos_valid = 0; 5922 flush_len = 0; 5923 } 5924 if (flush_pos_valid == 0) { 5925 flush_pos_valid = 1; 5926 flush_pos = fba_pos + sblk; 5927 } 5928 flush_len += len; 5929 } 5930 fba_pos += BLK_FBAS; 5931 cc_ent = cc_ent->cc_chain; 5932 /* 5933 * If we find a gap, write out what we've got 5934 */ 5935 if (flush_pos_valid && (flush_pos + flush_len) != fba_pos) { 5936 (void) _sd_write(handle, flush_pos, flush_len, 5937 NSC_QUEUE); 5938 flush_pos_valid = 0; 5939 flush_len = 0; 5940 } 5941 } 5942 if (flush_pos_valid) 5943 (void) _sd_write(handle, flush_pos, flush_len, NSC_QUEUE); 5944 } 5945 5946 5947 static int 5948 _sd_remote_store(_sd_cctl_t *cc_ent, nsc_off_t fba_pos, nsc_size_t fba_len) 5949 { 5950 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 5951 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 5952 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 5953 ss_resource_t *ss_res; 5954 5955 if (_sd_nodes_configured <= 2 && _sd_is_mirror_down()) 5956 return (0); 5957 st_cblk_off = BLK_FBA_OFF(fba_pos); 5958 st_cblk_len = BLK_FBAS - st_cblk_off; 5959 if ((nsc_size_t)st_cblk_len >= fba_len) { 5960 end_cblk_len = 0; 5961 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 5962 } else { 5963 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 5964 } 5965 5966 fba_len -= st_cblk_len; 5967 5968 ss_res = cc_ent->cc_write->sc_res; 5969 if (SSOP_WRITE_CBLOCK(sdbc_safestore, ss_res, 5970 cc_ent->cc_data + FBA_SIZE(st_cblk_off), FBA_SIZE(st_cblk_len), 5971 FBA_SIZE(st_cblk_off))) { 5972 5973 cmn_err(CE_WARN, 5974 "!sdbc(_sd_write) safe store failed. Going synchronous"); 5975 SDTRACE(SDF_REFLECT, CENTRY_CD(cc_ent), fba_len, 5976 fba_pos, 0, -1); 5977 return (-1); 5978 } 5979 5980 cc_ent = cc_ent->cc_chain; 5981 while (fba_len > (nsc_size_t)end_cblk_len) { 5982 fba_len -= BLK_FBAS; 5983 5984 if (SSOP_WRITE_CBLOCK(sdbc_safestore, ss_res, cc_ent->cc_data, 5985 CACHE_BLOCK_SIZE, 0)) { 5986 5987 cmn_err(CE_WARN, "!sdbc(_sd_write) safe store failed. " 5988 "Going synchronous"); 5989 SDTRACE(SDF_REFLECT, CENTRY_CD(cc_ent), fba_len, 5990 fba_pos, 0, -1); 5991 return (-1); 5992 } 5993 5994 cc_ent = cc_ent->cc_chain; 5995 } /* end while */ 5996 5997 if (fba_len) { 5998 if (SSOP_WRITE_CBLOCK(sdbc_safestore, ss_res, 5999 cc_ent->cc_data, FBA_SIZE(end_cblk_len), 0)) { 6000 6001 cmn_err(CE_WARN, "!sdbc(_sd_write) nvmem dma failed. " 6002 "Going synchronous"); 6003 SDTRACE(SDF_REFLECT, CENTRY_CD(cc_ent), fba_len, 6004 fba_pos, 0, -1); 6005 return (-1); 6006 } 6007 } 6008 return (0); 6009 } 6010 6011 6012 /* 6013 * _sd_sync_write2 - Write-through function. 6014 * 6015 * ARGUMENTS: 6016 * wr_handle - handle into which to write the data. 6017 * wr_st_pos - starting FBA position in wr_handle. 6018 * fba_len - length in fbas. 6019 * flag - NSC_NOBLOCK for async io. 6020 * rd_handle - handle from which to read the data, or NULL. 6021 * rd_st_pos - starting FBA position in rd_handle. 6022 * 6023 * RETURNS: 6024 * errno if return > 0 6025 * NSC_DONE or NSC_PENDING otherwise. 6026 * 6027 * Comments: 6028 * This routine initiates io of the indicated portion. It returns 6029 * synchronously after io is completed if NSC_NOBLOCK is not set. 6030 * Else NSC_PENDING is returned with a subsequent write callback on 6031 * io completion. 6032 * 6033 * See _sd_copy_direct() for usage when 6034 * (wr_handle != rd_handle && rd_handle != NULL) 6035 */ 6036 6037 static int 6038 _sd_sync_write2(_sd_buf_handle_t *wr_handle, nsc_off_t wr_st_pos, 6039 nsc_size_t fba_len, int flag, _sd_buf_handle_t *rd_handle, 6040 nsc_off_t rd_st_pos) 6041 { 6042 void (*fn)(blind_t, nsc_off_t, nsc_size_t, int); 6043 _sd_cctl_t *wr_ent, *rd_ent; 6044 nsc_size_t this_len; 6045 nsc_off_t rd_pos, wr_pos; 6046 nsc_size_t log_bytes; 6047 int cd = HANDLE_CD(wr_handle); 6048 int err; 6049 uint_t dirty; 6050 struct buf *bp; 6051 6052 LINTUSED(flag); 6053 6054 _SD_DISCONNECT_CALLBACK(wr_handle); 6055 6056 if (rd_handle == NULL) { 6057 rd_handle = wr_handle; 6058 rd_st_pos = wr_st_pos; 6059 } 6060 6061 wr_ent = wr_handle->bh_centry; 6062 while (CENTRY_BLK(wr_ent) != FBA_TO_BLK_NUM(wr_st_pos)) 6063 wr_ent = wr_ent->cc_chain; 6064 6065 rd_ent = rd_handle->bh_centry; 6066 while (CENTRY_BLK(rd_ent) != FBA_TO_BLK_NUM(rd_st_pos)) 6067 rd_ent = rd_ent->cc_chain; 6068 6069 bp = sd_alloc_iob(_sd_cache_files[cd].cd_crdev, 6070 wr_st_pos, FBA_TO_BLK_LEN(fba_len) + 2, B_WRITE); 6071 6072 if (bp == NULL) 6073 return (E2BIG); 6074 6075 wr_pos = BLK_FBA_OFF(wr_st_pos); 6076 rd_pos = BLK_FBA_OFF(rd_st_pos); 6077 log_bytes = 0; 6078 6079 do { 6080 this_len = min((BLK_FBAS - rd_pos), (BLK_FBAS - wr_pos)); 6081 6082 if (this_len > fba_len) 6083 this_len = fba_len; 6084 6085 /* 6086 * clear dirty bits in the write handle. 6087 */ 6088 6089 if (CENTRY_DIRTY(wr_ent)) { 6090 mutex_enter(&wr_ent->cc_lock); 6091 6092 if (CENTRY_DIRTY(wr_ent)) { 6093 if (this_len == (nsc_size_t)BLK_FBAS || 6094 rd_handle != wr_handle) { 6095 /* 6096 * optimization for when we have a 6097 * full cache block, or are doing 6098 * copy_direct (see below). 6099 */ 6100 6101 wr_ent->cc_write->sc_dirty = 0; 6102 } else { 6103 dirty = wr_ent->cc_write->sc_dirty; 6104 dirty &= ~(SDBC_GET_BITS( 6105 wr_pos, this_len)); 6106 wr_ent->cc_write->sc_dirty = dirty; 6107 } 6108 6109 SSOP_SETCENTRY(sdbc_safestore, 6110 wr_ent->cc_write); 6111 } 6112 6113 mutex_exit(&wr_ent->cc_lock); 6114 } 6115 6116 /* 6117 * update valid bits in the write handle. 6118 */ 6119 6120 if (rd_handle == wr_handle) { 6121 if (this_len == (nsc_size_t)BLK_FBAS) { 6122 SET_FULLY_VALID(wr_ent); 6123 } else { 6124 SDBC_SET_VALID_BITS(wr_pos, this_len, wr_ent); 6125 } 6126 } else { 6127 /* 6128 * doing copy_direct, so mark the write handle 6129 * as invalid since the data is on disk, but not 6130 * in cache. 6131 */ 6132 wr_ent->cc_valid = 0; 6133 } 6134 6135 DATA_LOG(SDF_WRSYNC, rd_ent, rd_pos, this_len); 6136 6137 DTRACE_PROBE4(_sd_sync_write2_data, uint64_t, 6138 (uint64_t)BLK_TO_FBA_NUM(CENTRY_BLK(rd_ent)) + rd_pos, 6139 uint64_t, (uint64_t)this_len, char *, 6140 *(int64_t *)(rd_ent->cc_data + FBA_SIZE(rd_pos)), 6141 char *, *(int64_t *)(rd_ent->cc_data + 6142 FBA_SIZE(rd_pos + this_len) - 8)); 6143 6144 sd_add_fba(bp, &rd_ent->cc_addr, rd_pos, this_len); 6145 6146 log_bytes += FBA_SIZE(this_len); 6147 fba_len -= this_len; 6148 6149 wr_pos += this_len; 6150 if (wr_pos >= (nsc_size_t)BLK_FBAS) { 6151 wr_ent = wr_ent->cc_chain; 6152 wr_pos = 0; 6153 } 6154 6155 rd_pos += this_len; 6156 if (rd_pos >= (nsc_size_t)BLK_FBAS) { 6157 rd_ent = rd_ent->cc_chain; 6158 rd_pos = 0; 6159 } 6160 6161 } while (fba_len > 0); 6162 6163 DISK_FBA_WRITE(cd, FBA_NUM(log_bytes)); 6164 CACHE_WRITE_MISS; 6165 6166 FBA_WRITE_IO_KSTATS(cd, log_bytes); 6167 6168 fn = (wr_handle->bh_flag & NSC_NOBLOCK) ? _sd_async_write_ea : NULL; 6169 6170 err = sd_start_io(bp, _sd_cache_files[cd].cd_strategy, fn, wr_handle); 6171 6172 if (err != NSC_PENDING) { 6173 DATA_LOG_CHAIN(SDF_WRSYEA, wr_handle->bh_centry, 6174 wr_st_pos, FBA_NUM(log_bytes)); 6175 } 6176 6177 return (err); 6178 } 6179 6180 6181 static int 6182 _sd_sync_write(_sd_buf_handle_t *handle, nsc_off_t fba_pos, nsc_size_t fba_len, 6183 int flag) 6184 { 6185 return (_sd_sync_write2(handle, fba_pos, fba_len, flag, NULL, 0)); 6186 } 6187 6188 6189 /* 6190 * _sd_zero - Interface call to zero out a portion of cache blocks. 6191 * 6192 * ARGUMENTS: 6193 * handle - handle allocated earlier on. 6194 * fba_pos - disk block number to zero from. 6195 * fba_len - length in fbas. 6196 * flag - NSC_NOBLOCK for async io. 6197 * 6198 * RETURNS: 6199 * errno if return > 0 6200 * NSC_DONE or NSC_PENDING otherwise. 6201 * 6202 * Comments: 6203 * This routine zeroes out the indicated portion of the cache blocks 6204 * and commits the data to disk. 6205 * (See write for more details on the commit) 6206 */ 6207 6208 6209 int 6210 _sd_zero(_sd_buf_handle_t *handle, nsc_off_t fba_pos, nsc_size_t fba_len, 6211 int flag) 6212 { 6213 int cd; 6214 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 6215 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 6216 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 6217 nsc_size_t cur_fba_len; /* position in disk blocks */ 6218 int ret; 6219 _sd_cctl_t *cc_ent; 6220 6221 if (_sdbc_shutdown_in_progress) { 6222 DTRACE_PROBE(shutdown); 6223 return (EIO); 6224 } 6225 6226 if (!_SD_HANDLE_ACTIVE(handle)) { 6227 cmn_err(CE_WARN, "!sdbc(_sd_zero) handle %p not active", 6228 (void *)handle); 6229 6230 DTRACE_PROBE1(handle_active, int, handle->bh_flag); 6231 6232 return (EINVAL); 6233 } 6234 ASSERT_HANDLE_LIMITS(handle, fba_pos, fba_len); 6235 if ((handle->bh_flag & NSC_WRBUF) == 0) { 6236 DTRACE_PROBE1(handle_write, int, handle->bh_flag); 6237 return (EINVAL); 6238 } 6239 6240 if (fba_len == 0) { 6241 DTRACE_PROBE(zero_len); 6242 return (NSC_DONE); 6243 } 6244 6245 if (_SD_FORCE_DISCONNECT(fba_len)) 6246 _SD_DISCONNECT_CALLBACK(handle); 6247 6248 cd = HANDLE_CD(handle); 6249 SDTRACE(ST_ENTER|SDF_ZERO, cd, fba_len, fba_pos, flag, 0); 6250 6251 cc_ent = handle->bh_centry; 6252 while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos)) 6253 cc_ent = cc_ent->cc_chain; 6254 cur_fba_len = fba_len; 6255 st_cblk_off = BLK_FBA_OFF(fba_pos); 6256 st_cblk_len = BLK_FBAS - st_cblk_off; 6257 if ((nsc_size_t)st_cblk_len >= fba_len) { 6258 end_cblk_len = 0; 6259 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 6260 } else { 6261 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 6262 } 6263 6264 cur_fba_len -= st_cblk_len; 6265 bzero(cc_ent->cc_data + FBA_SIZE(st_cblk_off), FBA_SIZE(st_cblk_len)); 6266 6267 cc_ent = cc_ent->cc_chain; 6268 while (cur_fba_len > (nsc_size_t)end_cblk_len) { 6269 cur_fba_len -= BLK_FBAS; 6270 bzero(cc_ent->cc_data, CACHE_BLOCK_SIZE); 6271 cc_ent = cc_ent->cc_chain; 6272 } 6273 if (cur_fba_len) { 6274 bzero(cc_ent->cc_data, FBA_SIZE(cur_fba_len)); 6275 } 6276 6277 ret = _sd_write(handle, fba_pos, fba_len, flag); 6278 SDTRACE(ST_EXIT|SDF_ZERO, cd, fba_len, fba_pos, flag, ret); 6279 6280 return (ret); 6281 } 6282 6283 6284 /* 6285 * _sd_copy - Copies portions of 2 handles. 6286 * 6287 * ARGUMENTS: 6288 * handle1 - handle allocated earlier on. 6289 * handle2 - handle allocated earlier on. 6290 * fba_pos1 - disk block number to read from. 6291 * fba_pos2 - disk block number to write to. 6292 * fba_len - length in fbas. 6293 * 6294 * RETURNS: 6295 * errno if return > 0 6296 * NSC_DONE otherwise. 6297 * 6298 * Comments: 6299 * This routine copies the 2 handles. 6300 * WARNING: this could put the cache blocks in the destination handle 6301 * in an inconsistent state. (the blocks could be valid in cache, 6302 * but the copy makes the cache different from disk) 6303 * 6304 */ 6305 6306 6307 int 6308 _sd_copy(_sd_buf_handle_t *handle1, _sd_buf_handle_t *handle2, 6309 nsc_off_t fba_pos1, nsc_off_t fba_pos2, nsc_size_t fba_len) 6310 { 6311 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 6312 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 6313 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 6314 nsc_off_t off1, off2; /* offsets in FBA's into the disk */ 6315 nsc_size_t cur_fba_len; /* position in disk blocks */ 6316 _sd_cctl_t *cc_ent1, *cc_ent2; 6317 6318 if (_sdbc_shutdown_in_progress) { 6319 DTRACE_PROBE(shutdown); 6320 return (EIO); 6321 } 6322 if (!_SD_HANDLE_ACTIVE(handle1) || !_SD_HANDLE_ACTIVE(handle2)) { 6323 cmn_err(CE_WARN, "!sdbc(_sd_copy) handle %p or %p not active", 6324 (void *)handle1, (void *)handle2); 6325 6326 DTRACE_PROBE2(handle_active1, int, handle1->bh_flag, 6327 int, handle2->bh_flag); 6328 6329 return (EINVAL); 6330 } 6331 ASSERT_HANDLE_LIMITS(handle1, fba_pos1, fba_len); 6332 ASSERT_HANDLE_LIMITS(handle2, fba_pos2, fba_len); 6333 6334 cc_ent1 = handle1->bh_centry; 6335 while (CENTRY_BLK(cc_ent1) != FBA_TO_BLK_NUM(fba_pos1)) 6336 cc_ent1 = cc_ent1->cc_chain; 6337 6338 cc_ent2 = handle2->bh_centry; 6339 while (CENTRY_BLK(cc_ent2) != FBA_TO_BLK_NUM(fba_pos2)) 6340 cc_ent2 = cc_ent2->cc_chain; 6341 6342 if (BLK_FBA_OFF(fba_pos1) != BLK_FBA_OFF(fba_pos2)) { 6343 /* Different offsets, do it slowly (per fba) */ 6344 6345 while (fba_len) { 6346 off1 = FBA_SIZE(BLK_FBA_OFF(fba_pos1)); 6347 off2 = FBA_SIZE(BLK_FBA_OFF(fba_pos2)); 6348 6349 bcopy(cc_ent1->cc_data+off1, cc_ent2->cc_data+off2, 6350 FBA_SIZE(1)); 6351 6352 fba_pos1++; 6353 fba_pos2++; 6354 fba_len--; 6355 6356 if (FBA_TO_BLK_NUM(fba_pos1) != CENTRY_BLK(cc_ent1)) 6357 cc_ent1 = cc_ent1->cc_chain; 6358 if (FBA_TO_BLK_NUM(fba_pos2) != CENTRY_BLK(cc_ent2)) 6359 cc_ent2 = cc_ent2->cc_chain; 6360 } 6361 6362 DTRACE_PROBE(_sd_copy_end); 6363 return (NSC_DONE); 6364 } 6365 cur_fba_len = fba_len; 6366 st_cblk_off = BLK_FBA_OFF(fba_pos1); 6367 st_cblk_len = BLK_FBAS - st_cblk_off; 6368 if ((nsc_size_t)st_cblk_len >= fba_len) { 6369 end_cblk_len = 0; 6370 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 6371 } else { 6372 end_cblk_len = BLK_FBA_OFF(fba_pos1 + fba_len); 6373 } 6374 6375 bcopy(cc_ent1->cc_data + FBA_SIZE(st_cblk_off), 6376 cc_ent2->cc_data + FBA_SIZE(st_cblk_off), FBA_SIZE(st_cblk_len)); 6377 cur_fba_len -= st_cblk_len; 6378 cc_ent1 = cc_ent1->cc_chain; 6379 cc_ent2 = cc_ent2->cc_chain; 6380 6381 while (cur_fba_len > (nsc_size_t)end_cblk_len) { 6382 bcopy(cc_ent1->cc_data, cc_ent2->cc_data, CACHE_BLOCK_SIZE); 6383 cc_ent1 = cc_ent1->cc_chain; 6384 cc_ent2 = cc_ent2->cc_chain; 6385 cur_fba_len -= BLK_FBAS; 6386 } 6387 if (cur_fba_len) { 6388 bcopy(cc_ent1->cc_data, cc_ent2->cc_data, 6389 FBA_SIZE(end_cblk_len)); 6390 } 6391 6392 return (NSC_DONE); 6393 } 6394 6395 6396 /* 6397 * _sd_copy_direct - Copies data from one handle direct to another disk. 6398 * 6399 * ARGUMENTS: 6400 * handle1 - handle to read from 6401 * handle2 - handle to write to 6402 * fba_pos1 - disk block number to read from. 6403 * fba_pos2 - disk block number to write to. 6404 * fba_len - length in fbas. 6405 * 6406 * RETURNS: 6407 * errno if return > 0 6408 * NSC_DONE otherwise. 6409 * 6410 * Comments: 6411 * This routine copies data from handle1 directly (sync write) 6412 * onto the disk pointed to by handle2. The handle2 is then 6413 * invalidated since the data it contains is now stale compared to 6414 * the disk. 6415 */ 6416 6417 static int 6418 _sd_copy_direct(_sd_buf_handle_t *handle1, _sd_buf_handle_t *handle2, 6419 nsc_off_t fba_pos1, nsc_off_t fba_pos2, nsc_size_t fba_len) 6420 { 6421 int rc; 6422 6423 if (_sdbc_shutdown_in_progress) { 6424 DTRACE_PROBE(shutdown); 6425 return (EIO); 6426 } 6427 6428 if (!_SD_HANDLE_ACTIVE(handle1) || !_SD_HANDLE_ACTIVE(handle2)) { 6429 cmn_err(CE_WARN, 6430 "!sdbc(_sd_copy_direct) handle %p or %p not active", 6431 (void *)handle1, (void *)handle2); 6432 6433 DTRACE_PROBE2(handle_active2, int, handle1->bh_flag, 6434 int, handle2->bh_flag); 6435 6436 return (EINVAL); 6437 } 6438 6439 ASSERT_HANDLE_LIMITS(handle1, fba_pos1, fba_len); 6440 ASSERT_HANDLE_LIMITS(handle2, fba_pos2, fba_len); 6441 6442 if ((handle2->bh_flag & NSC_WRITE) == 0) { 6443 cmn_err(CE_WARN, 6444 "!sdbc(_sd_copy_direct) handle2 %p is not writeable", 6445 (void *)handle2); 6446 DTRACE_PROBE1(handle2_write, int, handle2->bh_flag); 6447 return (EINVAL); 6448 } 6449 6450 rc = _sd_sync_write2(handle2, fba_pos2, fba_len, 0, handle1, fba_pos1); 6451 6452 return (rc); 6453 } 6454 6455 6456 /* 6457 * _sd_enqueue_dirty - Enqueue a list of dirty buffers. 6458 * 6459 * ARGUMENTS: 6460 * cd - cache descriptor. 6461 * chain - pointer to list. 6462 * cc_last - last entry in the chain. 6463 * numq - number of entries in the list. 6464 * 6465 * RETURNS: 6466 * NONE. 6467 * 6468 * Comments: 6469 * This routine queues up the dirty blocks for io processing. 6470 * It uses the cc_last to try to coalesce multiple lists into a 6471 * single list, if consecutive writes are sequential in nature. 6472 */ 6473 6474 void 6475 _sd_enqueue_dirty(int cd, _sd_cctl_t *chain, _sd_cctl_t *cc_last, int numq) 6476 { 6477 _sd_cd_info_t *cdi; 6478 _sd_cctl_t *last_ent; 6479 int start_write = 0, maxq = SGIO_MAX; 6480 6481 ASSERT(cd >= 0); 6482 cdi = &(_sd_cache_files[cd]); 6483 #if defined(_SD_DEBUG) 6484 if (chain->cc_dirty_link) 6485 cmn_err(CE_WARN, "!dirty_link set in enq %x fl %x", 6486 chain->cc_dirty_link, chain->cc_flag); 6487 #endif 6488 6489 /* was FAST */ 6490 mutex_enter(&(cdi->cd_lock)); 6491 cdi->cd_info->sh_numdirty += numq; 6492 if (cc_last == NULL) 6493 numq = 0; 6494 6495 if (cdi->cd_dirty_head == NULL) { 6496 cdi->cd_dirty_head = cdi->cd_dirty_tail = chain; 6497 cdi->cd_last_ent = cc_last; 6498 cdi->cd_lastchain_ptr = chain; 6499 cdi->cd_lastchain = numq; 6500 } else { 6501 if ((cc_last) && (last_ent = cdi->cd_last_ent) && 6502 (CENTRY_BLK(chain) == (CENTRY_BLK(last_ent)+1)) && 6503 (SDBC_DIRTY_NEIGHBORS(last_ent, chain)) && 6504 (cdi->cd_lastchain + numq < maxq)) { 6505 cdi->cd_last_ent->cc_dirty_next = chain; 6506 cdi->cd_last_ent = cc_last; 6507 cdi->cd_lastchain += numq; 6508 } else { 6509 cdi->cd_dirty_tail->cc_dirty_link = chain; 6510 cdi->cd_dirty_tail = chain; 6511 cdi->cd_last_ent = cc_last; 6512 cdi->cd_lastchain_ptr = chain; 6513 cdi->cd_lastchain = numq; 6514 start_write = 1; 6515 } 6516 } 6517 /* was FAST */ 6518 mutex_exit(&(cdi->cd_lock)); 6519 if (start_write) 6520 (void) _SD_CD_WRITER(cd); 6521 } 6522 6523 /* 6524 * _sd_enqueue_dirty_chain - Enqueue a chain of a list of dirty buffers. 6525 * 6526 * ARGUMENTS: 6527 * cd - cache descriptor. 6528 * chain_first - first list in this chain. 6529 * chain_last - last list in this chain. 6530 * numq - number of entries being queue (total of all lists) 6531 * 6532 * RETURNS: 6533 * NONE. 6534 * 6535 * Comments: 6536 * This routine is called from the processing after io completions. 6537 * If the buffers are still dirty, they are queued up in one shot. 6538 */ 6539 6540 void 6541 _sd_enqueue_dirty_chain(int cd, _sd_cctl_t *chain_first, 6542 _sd_cctl_t *chain_last, int numq) 6543 { 6544 _sd_cd_info_t *cdi; 6545 6546 ASSERT(cd >= 0); 6547 cdi = &(_sd_cache_files[cd]); 6548 if (chain_last->cc_dirty_link) 6549 cmn_err(CE_PANIC, 6550 "!_sd_enqueue_dirty_chain: chain_last %p dirty_link %p", 6551 (void *)chain_last, (void *)chain_last->cc_dirty_link); 6552 /* was FAST */ 6553 mutex_enter(&(cdi->cd_lock)); 6554 cdi->cd_last_ent = NULL; 6555 cdi->cd_lastchain_ptr = NULL; 6556 cdi->cd_lastchain = 0; 6557 6558 cdi->cd_info->sh_numdirty += numq; 6559 if (cdi->cd_dirty_head == NULL) { 6560 cdi->cd_dirty_head = chain_first; 6561 cdi->cd_dirty_tail = chain_last; 6562 } else { 6563 cdi->cd_dirty_tail->cc_dirty_link = chain_first; 6564 cdi->cd_dirty_tail = chain_last; 6565 } 6566 /* was FAST */ 6567 mutex_exit(&(cdi->cd_lock)); 6568 } 6569 6570 /* 6571 * Convert the 64 bit statistic structure to 32bit version. 6572 * Possibly losing information when cache is > 4gb. Ha! 6573 * 6574 * NOTE: this code isn't really MT ready since the copied to struct 6575 * is static. However the race is pretty benign and isn't a whole 6576 * lot worse than the vanilla version which copies data to user 6577 * space from kernel structures that can be changing under it too. 6578 * We can't use a local stack structure since the data size is 6579 * 70k or so and kernel stacks are tiny (8k). 6580 */ 6581 #ifndef _MULTI_DATAMODEL 6582 /* ARGSUSED */ 6583 #endif 6584 static int 6585 convert_stats(_sd_stats32_t *uptr) 6586 { 6587 #ifndef _MULTI_DATAMODEL 6588 return (SDBC_EMODELCONVERT); 6589 #else 6590 int rc = 0; 6591 6592 /* 6593 * This could be done in less code with bcopy type operations 6594 * but this is simpler to follow and easier to change if 6595 * the structures change. 6596 */ 6597 6598 _sd_cache_stats32->net_dirty = _sd_cache_stats->net_dirty; 6599 _sd_cache_stats32->net_pending = _sd_cache_stats->net_pending; 6600 _sd_cache_stats32->net_free = _sd_cache_stats->net_free; 6601 _sd_cache_stats32->st_count = _sd_cache_stats->st_count; 6602 _sd_cache_stats32->st_loc_count = _sd_cache_stats->st_loc_count; 6603 _sd_cache_stats32->st_rdhits = _sd_cache_stats->st_rdhits; 6604 _sd_cache_stats32->st_rdmiss = _sd_cache_stats->st_rdmiss; 6605 _sd_cache_stats32->st_wrhits = _sd_cache_stats->st_wrhits; 6606 _sd_cache_stats32->st_wrmiss = _sd_cache_stats->st_wrmiss; 6607 _sd_cache_stats32->st_blksize = _sd_cache_stats->st_blksize; 6608 6609 _sd_cache_stats32->st_lru_blocks = _sd_cache_stats->st_lru_blocks; 6610 _sd_cache_stats32->st_lru_noreq = _sd_cache_stats->st_lru_noreq; 6611 _sd_cache_stats32->st_lru_req = _sd_cache_stats->st_lru_req; 6612 6613 _sd_cache_stats32->st_wlru_inq = _sd_cache_stats->st_wlru_inq; 6614 6615 _sd_cache_stats32->st_cachesize = _sd_cache_stats->st_cachesize; 6616 _sd_cache_stats32->st_numblocks = _sd_cache_stats->st_numblocks; 6617 _sd_cache_stats32->st_wrcancelns = _sd_cache_stats->st_wrcancelns; 6618 _sd_cache_stats32->st_destaged = _sd_cache_stats->st_destaged; 6619 6620 /* 6621 * bcopy the shared stats which has nothing that needs conversion 6622 * in them 6623 */ 6624 6625 bcopy(_sd_cache_stats->st_shared, _sd_cache_stats32->st_shared, 6626 sizeof (_sd_shared_t) * sdbc_max_devs); 6627 6628 if (copyout(_sd_cache_stats32, uptr, sizeof (_sd_stats32_t) + 6629 (sdbc_max_devs - 1) * sizeof (_sd_shared_t))) 6630 rc = EFAULT; 6631 6632 return (rc); 6633 #endif /* _MULTI_DATAMODEL */ 6634 } 6635 6636 6637 int 6638 _sd_get_stats(_sd_stats_t *uptr, int convert_32) 6639 { 6640 int rc = 0; 6641 6642 if (_sd_cache_stats == NULL) { 6643 static _sd_stats_t dummy; 6644 #ifdef _MULTI_DATAMODEL 6645 static _sd_stats32_t dummy32; 6646 #endif 6647 6648 if (convert_32) { 6649 #ifdef _MULTI_DATAMODEL 6650 if (copyout(&dummy32, uptr, sizeof (_sd_stats32_t))) 6651 rc = EFAULT; 6652 #else 6653 rc = SDBC_EMODELCONVERT; 6654 #endif 6655 } else if (copyout(&dummy, uptr, sizeof (_sd_stats_t))) 6656 rc = EFAULT; 6657 return (rc); 6658 } 6659 6660 _sd_cache_stats->st_lru_blocks = _sd_lru_q.sq_inq; 6661 _sd_cache_stats->st_lru_noreq = _sd_lru_q.sq_noreq_stat; 6662 _sd_cache_stats->st_lru_req = _sd_lru_q.sq_req_stat; 6663 6664 if (sdbc_safestore) { 6665 ssioc_stats_t ss_stats; 6666 6667 if (SSOP_CTL(sdbc_safestore, SSIOC_STATS, 6668 (uintptr_t)&ss_stats) == 0) 6669 _sd_cache_stats->st_wlru_inq = ss_stats.wq_inq; 6670 else 6671 _sd_cache_stats->st_wlru_inq = 0; 6672 } 6673 6674 if (convert_32) 6675 rc = convert_stats((_sd_stats32_t *)uptr); 6676 else if (copyout(_sd_cache_stats, uptr, 6677 sizeof (_sd_stats_t) + (sdbc_max_devs - 1) * sizeof (_sd_shared_t))) 6678 rc = EFAULT; 6679 6680 return (rc); 6681 } 6682 6683 6684 int 6685 _sd_set_hint(int cd, uint_t hint) 6686 { 6687 int ret = 0; 6688 if (FILE_OPENED(cd)) { 6689 SDTRACE(ST_ENTER|SDF_HINT, cd, 1, SDT_INV_BL, hint, 0); 6690 _sd_cache_files[cd].cd_hint |= (hint & _SD_HINT_MASK); 6691 SDTRACE(ST_EXIT|SDF_HINT, cd, 1, SDT_INV_BL, hint, ret); 6692 } else 6693 ret = EINVAL; 6694 6695 return (ret); 6696 } 6697 6698 6699 6700 int 6701 _sd_clear_hint(int cd, uint_t hint) 6702 { 6703 int ret = 0; 6704 if (FILE_OPENED(cd)) { 6705 SDTRACE(ST_ENTER|SDF_HINT, cd, 2, SDT_INV_BL, hint, 0); 6706 _sd_cache_files[cd].cd_hint &= ~(hint & _SD_HINT_MASK); 6707 SDTRACE(ST_EXIT|SDF_HINT, cd, 2, SDT_INV_BL, hint, ret); 6708 } else 6709 ret = EINVAL; 6710 6711 return (ret); 6712 } 6713 6714 6715 int 6716 _sd_get_cd_hint(int cd, uint_t *hint) 6717 { 6718 *hint = 0; 6719 if (FILE_OPENED(cd)) { 6720 *hint = _sd_cache_files[cd].cd_hint; 6721 return (0); 6722 } else 6723 return (EINVAL); 6724 } 6725 6726 static int 6727 _sd_node_hint_caller(blind_t hint, int hint_action) 6728 { 6729 int rc; 6730 6731 switch (hint_action) { 6732 case NSC_GET_NODE_HINT: 6733 rc = _sd_get_node_hint((uint_t *)hint); 6734 break; 6735 case NSC_SET_NODE_HINT: 6736 rc = _sd_set_node_hint((uint_t)(unsigned long)hint); 6737 break; 6738 case NSC_CLEAR_NODE_HINT: 6739 rc = _sd_clear_node_hint((uint_t)(unsigned long)hint); 6740 break; 6741 default: 6742 rc = EINVAL; 6743 break; 6744 } 6745 6746 return (rc); 6747 } 6748 6749 int 6750 _sd_set_node_hint(uint_t hint) 6751 { 6752 SDTRACE(ST_ENTER|SDF_HINT, SDT_INV_CD, 3, SDT_INV_BL, hint, 0); 6753 if ((_sd_node_hint & NSC_NO_FORCED_WRTHRU) && 6754 (hint & NSC_FORCED_WRTHRU)) 6755 return (EINVAL); 6756 _sd_node_hint |= (hint & _SD_HINT_MASK); 6757 SDTRACE(ST_EXIT|SDF_HINT, SDT_INV_CD, 3, SDT_INV_BL, hint, 0); 6758 return (0); 6759 } 6760 6761 6762 int 6763 _sd_clear_node_hint(uint_t hint) 6764 { 6765 SDTRACE(ST_ENTER|SDF_HINT, SDT_INV_CD, 4, SDT_INV_BL, hint, 0); 6766 _sd_node_hint &= ~(hint & _SD_HINT_MASK); 6767 SDTRACE(ST_EXIT|SDF_HINT, SDT_INV_CD, 4, SDT_INV_BL, hint, 0); 6768 return (0); 6769 } 6770 6771 6772 int 6773 _sd_get_node_hint(uint_t *hint) 6774 { 6775 *hint = _sd_node_hint; 6776 return (0); 6777 } 6778 6779 6780 int 6781 _sd_get_partsize(blind_t xcd, nsc_size_t *ptr) 6782 { 6783 int cd = (int)(unsigned long)xcd; 6784 6785 if (FILE_OPENED(cd)) { 6786 *ptr = _sd_cache_files[cd].cd_info->sh_filesize; 6787 return (0); 6788 } else 6789 return (EINVAL); 6790 } 6791 6792 6793 int 6794 _sd_get_maxfbas(blind_t xcd, int flag, nsc_size_t *ptr) 6795 { 6796 int cd = (int)(unsigned long)xcd; 6797 6798 if (!FILE_OPENED(cd)) 6799 return (EINVAL); 6800 6801 if (flag & NSC_CACHEBLK) 6802 *ptr = BLK_FBAS; 6803 else 6804 *ptr = sdbc_max_fbas; 6805 6806 return (0); 6807 } 6808 6809 6810 int 6811 _sd_control(blind_t xcd, int cmd, void *ptr, int len) 6812 { 6813 _sd_cd_info_t *cdi; 6814 int cd = (int)(unsigned long)xcd; 6815 6816 cdi = &(_sd_cache_files[cd]); 6817 return (nsc_control(cdi->cd_rawfd, cmd, ptr, len)); 6818 } 6819 6820 6821 int 6822 _sd_discard_pinned(blind_t xcd, nsc_off_t fba_pos, nsc_size_t fba_len) 6823 { 6824 int cd = (int)(unsigned long)xcd; 6825 _sd_cctl_t *cc_ent, **cc_lst, **cc_tmp, *nxt; 6826 ss_centry_info_t *wctl; 6827 int found = 0; 6828 nsc_off_t cblk; 6829 _sd_cd_info_t *cdi = &_sd_cache_files[cd]; 6830 int rc; 6831 6832 if ((!FILE_OPENED(cd)) || (!cdi->cd_info->sh_failed)) { 6833 6834 return (EINVAL); 6835 } 6836 6837 for (cblk = FBA_TO_BLK_NUM(fba_pos); 6838 cblk < FBA_TO_BLK_LEN(fba_pos + fba_len); cblk++) { 6839 if (cc_ent = 6840 (_sd_cctl_t *)_sd_hash_search(cd, cblk, _sd_htable)) { 6841 if (!CENTRY_PINNED(cc_ent)) 6842 continue; 6843 6844 /* 6845 * remove cc_ent from failed links 6846 * cc_lst - pointer to "cc_dirty_link" pointer 6847 * starts at &cd_failed_head. 6848 * cc_tmp - pointer to "cc_dirty_next" 6849 * except when equal to cc_lst. 6850 */ 6851 mutex_enter(&cdi->cd_lock); 6852 cc_tmp = cc_lst = &(cdi->cd_fail_head); 6853 while (*cc_tmp != cc_ent) { 6854 cc_tmp = &((*cc_tmp)->cc_dirty_next); 6855 if (!*cc_tmp) 6856 cc_lst = &((*cc_lst)->cc_dirty_link), 6857 cc_tmp = cc_lst; 6858 } 6859 if (*cc_tmp) { 6860 found++; 6861 if (cc_lst != cc_tmp) /* break chain */ 6862 *cc_tmp = NULL; 6863 nxt = cc_ent->cc_dirty_next; 6864 if (nxt) { 6865 nxt->cc_dirty_link = 6866 (*cc_lst)->cc_dirty_link; 6867 *cc_lst = nxt; 6868 } else { 6869 *cc_lst = (*cc_lst)->cc_dirty_link; 6870 } 6871 cdi->cd_info->sh_numfail--; 6872 nsc_unpinned_data(cdi->cd_iodev, 6873 BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)), 6874 BLK_FBAS); 6875 } 6876 mutex_exit(&cdi->cd_lock); 6877 6878 /* clear dirty bits */ 6879 /* was FAST */ 6880 mutex_enter(&cc_ent->cc_lock); 6881 cc_ent->cc_valid = cc_ent->cc_dirty = 0; 6882 cc_ent->cc_flag &= ~(CC_QHEAD|CC_PEND_DIRTY|CC_PINNED); 6883 cc_ent->cc_dirty_link = NULL; 6884 wctl = cc_ent->cc_write; 6885 cc_ent->cc_write = NULL; 6886 /* was FAST */ 6887 mutex_exit(&cc_ent->cc_lock); 6888 6889 /* release cache block to head of LRU */ 6890 if (wctl) { 6891 wctl->sc_flag = 0; 6892 wctl->sc_dirty = 0; 6893 SSOP_SETCENTRY(sdbc_safestore, wctl); 6894 SSOP_DEALLOCRESOURCE(sdbc_safestore, 6895 wctl->sc_res); 6896 } 6897 6898 if (!sdbc_use_dmchain) 6899 _sd_requeue_head(cc_ent); 6900 } 6901 } 6902 6903 rc = found ? NSC_DONE : EINVAL; 6904 6905 return (rc); 6906 } 6907 6908 6909 /* 6910 * Handle allocation 6911 */ 6912 6913 _sd_buf_hlist_t _sd_handle_list; 6914 6915 /* 6916 * _sdbc_handles_unload - cache is being unloaded. 6917 */ 6918 void 6919 _sdbc_handles_unload(void) 6920 { 6921 mutex_destroy(&_sd_handle_list.hl_lock); 6922 6923 } 6924 6925 /* 6926 * _sdbc_handles_load - cache is being unloaded. 6927 */ 6928 int 6929 _sdbc_handles_load(void) 6930 { 6931 mutex_init(&_sd_handle_list.hl_lock, NULL, MUTEX_DRIVER, NULL); 6932 6933 return (0); 6934 } 6935 6936 int 6937 _sdbc_handles_configure() 6938 { 6939 _sd_handle_list.hl_count = 0; 6940 6941 _sd_handle_list.hl_top.bh_next = &_sd_handle_list.hl_top; 6942 _sd_handle_list.hl_top.bh_prev = &_sd_handle_list.hl_top; 6943 6944 return (0); 6945 } 6946 6947 6948 6949 /* 6950 * _sdbc_handles_deconfigure - cache is being deconfigured 6951 */ 6952 void 6953 _sdbc_handles_deconfigure(void) 6954 { 6955 _sd_handle_list.hl_count = 0; 6956 } 6957 6958 6959 _sd_buf_handle_t * 6960 _sd_alloc_handle(sdbc_callback_fn_t d_cb, sdbc_callback_fn_t r_cb, 6961 sdbc_callback_fn_t w_cb) 6962 { 6963 _sd_buf_handle_t *handle; 6964 6965 handle = (_sd_buf_handle_t *)kmem_zalloc(sizeof (_sd_buf_handle_t), 6966 KM_SLEEP); 6967 /* maintain list and count for debugging */ 6968 mutex_enter(&_sd_handle_list.hl_lock); 6969 6970 handle->bh_prev = &_sd_handle_list.hl_top; 6971 handle->bh_next = _sd_handle_list.hl_top.bh_next; 6972 _sd_handle_list.hl_top.bh_next->bh_prev = handle; 6973 _sd_handle_list.hl_top.bh_next = handle; 6974 6975 ++_sd_handle_list.hl_count; 6976 mutex_exit(&_sd_handle_list.hl_lock); 6977 #if !defined(_SD_NOCHECKS) 6978 ASSERT(!(handle->bh_flag & (NSC_HALLOCATED | NSC_HACTIVE))); 6979 #endif 6980 handle->bh_disconnect_cb = d_cb; 6981 handle->bh_read_cb = r_cb; 6982 handle->bh_write_cb = w_cb; 6983 handle->bh_flag |= NSC_HALLOCATED; 6984 handle->bh_alloc_thread = nsc_threadp(); 6985 6986 return (handle); 6987 } 6988 6989 int 6990 _sd_free_handle(_sd_buf_handle_t *handle) 6991 { 6992 6993 if ((handle->bh_flag & NSC_HALLOCATED) == 0) { 6994 cmn_err(CE_WARN, "!sdbc(_sd_free_handle) handle %p not valid", 6995 (void *)handle); 6996 6997 DTRACE_PROBE(_sd_free_handle_end); 6998 6999 return (EINVAL); 7000 } 7001 if (_SD_HANDLE_ACTIVE(handle)) { 7002 cmn_err(CE_WARN, 7003 "!sdbc(_sd_free_handle) attempt to free active handle %p", 7004 (void *)handle); 7005 7006 DTRACE_PROBE1(free_handle_active, int, handle->bh_flag); 7007 7008 return (EINVAL); 7009 } 7010 7011 7012 /* remove from queue before free */ 7013 mutex_enter(&_sd_handle_list.hl_lock); 7014 handle->bh_prev->bh_next = handle->bh_next; 7015 handle->bh_next->bh_prev = handle->bh_prev; 7016 --_sd_handle_list.hl_count; 7017 mutex_exit(&_sd_handle_list.hl_lock); 7018 7019 kmem_free(handle, sizeof (_sd_buf_handle_t)); 7020 7021 return (0); 7022 } 7023 7024 7025 7026 7027 #if !defined (_SD_8K_BLKSIZE) 7028 #define _SD_MAX_MAP 0x100 7029 #else /* !(_SD_8K_BLKSIZE) */ 7030 #define _SD_MAX_MAP 0x10000 7031 #endif /* !(_SD_8K_BLKSIZE) */ 7032 7033 char _sd_contig_bmap[_SD_MAX_MAP]; 7034 _sd_map_info_t _sd_lookup_map[_SD_MAX_MAP]; 7035 7036 void 7037 _sd_init_contig_bmap(void) 7038 { 7039 int i, j; 7040 7041 for (i = 1; i < _SD_MAX_MAP; i = ((i << 1) | 1)) 7042 for (j = i; j < _SD_MAX_MAP; j <<= 1) 7043 _sd_contig_bmap[j] = 1; 7044 } 7045 7046 7047 7048 7049 void 7050 _sd_init_lookup_map(void) 7051 { 7052 unsigned int i, j, k; 7053 int stpos, len; 7054 _sd_bitmap_t mask; 7055 7056 for (i = 0; i < _SD_MAX_MAP; i++) { 7057 for (j = i, k = 0; j && ((j & 1) == 0); j >>= 1, k++) 7058 ; 7059 stpos = k; 7060 _sd_lookup_map[i].mi_stpos = (unsigned char)k; 7061 7062 for (k = 0; j & 1; j >>= 1, k++) 7063 ; 7064 len = k; 7065 _sd_lookup_map[i].mi_len = (unsigned char)k; 7066 7067 _sd_lookup_map[i].mi_mask = SDBC_GET_BITS(stpos, len); 7068 } 7069 for (i = 0; i < _SD_MAX_MAP; i++) { 7070 mask = (_sd_bitmap_t)i; 7071 for (j = 0; mask; j++) 7072 SDBC_LOOKUP_MODIFY(mask); 7073 7074 _sd_lookup_map[i].mi_dirty_count = (unsigned char)j; 7075 } 7076 for (i = 0; i < _SD_MAX_MAP; i++) { 7077 _sd_lookup_map[i].mi_io_count = SDBC_LOOKUP_DTCOUNT(i); 7078 mask = ~i; 7079 _sd_lookup_map[i].mi_io_count += SDBC_LOOKUP_DTCOUNT(mask); 7080 } 7081 } 7082 7083 7084 nsc_def_t _sd_sdbc_def[] = { 7085 "Open", (uintptr_t)_sd_open_io, 0, 7086 "Close", (uintptr_t)_sd_close_io, 0, 7087 "Attach", (uintptr_t)_sdbc_io_attach_cd, 0, 7088 "Detach", (uintptr_t)_sdbc_io_detach_cd, 0, 7089 "AllocBuf", (uintptr_t)_sd_alloc_buf, 0, 7090 "FreeBuf", (uintptr_t)_sd_free_buf, 0, 7091 "Read", (uintptr_t)_sd_read, 0, 7092 "Write", (uintptr_t)_sd_write, 0, 7093 "Zero", (uintptr_t)_sd_zero, 0, 7094 "Copy", (uintptr_t)_sd_copy, 0, 7095 "CopyDirect", (uintptr_t)_sd_copy_direct, 0, 7096 "Uncommit", (uintptr_t)_sd_uncommit, 0, 7097 "AllocHandle", (uintptr_t)_sd_alloc_handle, 0, 7098 "FreeHandle", (uintptr_t)_sd_free_handle, 0, 7099 "Discard", (uintptr_t)_sd_discard_pinned, 0, 7100 "Sizes", (uintptr_t)_sd_cache_sizes, 0, 7101 "GetPinned", (uintptr_t)_sd_get_pinned, 0, 7102 "NodeHints", (uintptr_t)_sd_node_hint_caller, 0, 7103 "PartSize", (uintptr_t)_sd_get_partsize, 0, 7104 "MaxFbas", (uintptr_t)_sd_get_maxfbas, 0, 7105 "Control", (uintptr_t)_sd_control, 0, 7106 "Provide", NSC_CACHE, 0, 7107 0, 0, 0 7108 }; 7109 7110 /* 7111 * do the SD_GET_CD_CLUSTER_DATA ioctl (get the global filename data) 7112 */ 7113 /* ARGSUSED */ 7114 int 7115 sd_get_file_info_data(char *uaddrp) 7116 { 7117 return (ENOTTY); 7118 } 7119 7120 /* 7121 * do the SD_GET_CD_CLUSTER_SIZE ioctl (get size of global filename area) 7122 */ 7123 int 7124 sd_get_file_info_size(void *uaddrp) 7125 { 7126 if (copyout(&_sdbc_gl_file_info_size, uaddrp, 7127 sizeof (_sdbc_gl_file_info_size))) { 7128 return (EFAULT); 7129 } 7130 7131 return (0); 7132 } 7133 7134 7135 /* 7136 * SD_GET_GLMUL_SIZES ioctl 7137 * get sizes of the global info regions (for this node only) 7138 */ 7139 /* ARGSUSED */ 7140 int 7141 sd_get_glmul_sizes(int *uaddrp) 7142 { 7143 return (ENOTTY); 7144 } 7145 7146 /* 7147 * SD_GET_GLMUL_INFO ioctl 7148 * get the global metadata for write blocks (for this node only) 7149 */ 7150 /* ARGSUSED */ 7151 int 7152 sd_get_glmul_info(char *uaddrp) 7153 { 7154 7155 return (ENOTTY); 7156 } 7157 7158 int 7159 sdbc_global_stats_update(kstat_t *ksp, int rw) 7160 { 7161 sdbc_global_stats_t *sdbc_gstats; 7162 _sd_stats_t *gstats_vars; 7163 uint_t hint; 7164 7165 sdbc_gstats = (sdbc_global_stats_t *)(ksp->ks_data); 7166 7167 gstats_vars = _sd_cache_stats; 7168 7169 if (rw == KSTAT_WRITE) { 7170 return (EACCES); 7171 } 7172 7173 /* default to READ */ 7174 sdbc_gstats->ci_sdbc_count.value.ul = gstats_vars->st_count; 7175 sdbc_gstats->ci_sdbc_loc_count.value.ul = gstats_vars->st_loc_count; 7176 sdbc_gstats->ci_sdbc_rdhits.value.ul = (ulong_t)gstats_vars->st_rdhits; 7177 sdbc_gstats->ci_sdbc_rdmiss.value.ul = (ulong_t)gstats_vars->st_rdmiss; 7178 sdbc_gstats->ci_sdbc_wrhits.value.ul = (ulong_t)gstats_vars->st_wrhits; 7179 sdbc_gstats->ci_sdbc_wrmiss.value.ul = (ulong_t)gstats_vars->st_wrmiss; 7180 7181 sdbc_gstats->ci_sdbc_blksize.value.ul = 7182 (ulong_t)gstats_vars->st_blksize; 7183 sdbc_gstats->ci_sdbc_lru_blocks.value.ul = (ulong_t)_sd_lru_q.sq_inq; 7184 #ifdef DEBUG 7185 sdbc_gstats->ci_sdbc_lru_noreq.value.ul = 7186 (ulong_t)_sd_lru_q.sq_noreq_stat; 7187 sdbc_gstats->ci_sdbc_lru_req.value.ul = (ulong_t)_sd_lru_q.sq_req_stat; 7188 #endif 7189 sdbc_gstats->ci_sdbc_wlru_inq.value.ul = 7190 (ulong_t)gstats_vars->st_wlru_inq; 7191 sdbc_gstats->ci_sdbc_cachesize.value.ul = 7192 (ulong_t)gstats_vars->st_cachesize; 7193 sdbc_gstats->ci_sdbc_numblocks.value.ul = 7194 (ulong_t)gstats_vars->st_numblocks; 7195 sdbc_gstats->ci_sdbc_wrcancelns.value.ul = 7196 (ulong_t)gstats_vars->st_wrcancelns; 7197 sdbc_gstats->ci_sdbc_destaged.value.ul = 7198 (ulong_t)gstats_vars->st_destaged; 7199 sdbc_gstats->ci_sdbc_num_shared.value.ul = (ulong_t)sdbc_max_devs; 7200 (void) _sd_get_node_hint(&hint); 7201 sdbc_gstats->ci_sdbc_nodehints.value.ul = (ulong_t)hint; 7202 7203 7204 return (0); 7205 } 7206 7207 int 7208 sdbc_cd_stats_update(kstat_t *ksp, int rw) 7209 { 7210 sdbc_cd_stats_t *sdbc_shstats; 7211 _sd_shared_t *shstats_vars; 7212 int name_len; 7213 uint_t hint; 7214 7215 sdbc_shstats = (sdbc_cd_stats_t *)(ksp->ks_data); 7216 7217 shstats_vars = (_sd_shared_t *)(ksp->ks_private); 7218 7219 if (rw == KSTAT_WRITE) { 7220 return (EACCES); 7221 } 7222 7223 /* copy tail of filename to kstat. leave 1 byte for null char */ 7224 if (shstats_vars->sh_filename != NULL) { 7225 name_len = (int)strlen(shstats_vars->sh_filename); 7226 name_len -= (KSTAT_DATA_CHAR_LEN - 1); 7227 7228 if (name_len < 0) { 7229 name_len = 0; 7230 } 7231 7232 (void) strlcpy(sdbc_shstats->ci_sdbc_vol_name.value.c, 7233 shstats_vars->sh_filename + name_len, KSTAT_DATA_CHAR_LEN); 7234 } else { 7235 cmn_err(CE_WARN, "!Kstat error: no volume name associated " 7236 "with cache descriptor"); 7237 } 7238 7239 sdbc_shstats->ci_sdbc_failed.value.ul = 7240 (ulong_t)shstats_vars->sh_failed; 7241 sdbc_shstats->ci_sdbc_cd.value.ul = (ulong_t)shstats_vars->sh_cd; 7242 sdbc_shstats->ci_sdbc_cache_read.value.ul = 7243 (ulong_t)shstats_vars->sh_cache_read; 7244 sdbc_shstats->ci_sdbc_cache_write.value.ul = 7245 (ulong_t)shstats_vars->sh_cache_write; 7246 sdbc_shstats->ci_sdbc_disk_read.value.ul = 7247 (ulong_t)shstats_vars->sh_disk_read; 7248 sdbc_shstats->ci_sdbc_disk_write.value.ul = 7249 (ulong_t)shstats_vars->sh_disk_write; 7250 #ifdef NSC_MULTI_TERABYTE 7251 sdbc_shstats->ci_sdbc_filesize.value.ui64 = 7252 (uint64_t)shstats_vars->sh_filesize; 7253 #else 7254 sdbc_shstats->ci_sdbc_filesize.value.ul = 7255 (ulong_t)shstats_vars->sh_filesize; 7256 #endif 7257 sdbc_shstats->ci_sdbc_numdirty.value.ul = 7258 (ulong_t)shstats_vars->sh_numdirty; 7259 sdbc_shstats->ci_sdbc_numio.value.ul = (ulong_t)shstats_vars->sh_numio; 7260 sdbc_shstats->ci_sdbc_numfail.value.ul = 7261 (ulong_t)shstats_vars->sh_numfail; 7262 sdbc_shstats->ci_sdbc_destaged.value.ul = 7263 (ulong_t)shstats_vars->sh_destaged; 7264 sdbc_shstats->ci_sdbc_wrcancelns.value.ul = 7265 (ulong_t)shstats_vars->sh_wrcancelns; 7266 (void) _sd_get_cd_hint(shstats_vars->sh_cd, &hint); 7267 sdbc_shstats->ci_sdbc_cdhints.value.ul = (ulong_t)hint; 7268 7269 7270 return (0); 7271 } 7272 7273 7274 /* 7275 * cd_kstat_add 7276 * 7277 * Installs all kstats and associated infrastructure (mutex, buffer), 7278 * associated with a particular cache descriptor. This function is called 7279 * when the cache descriptor is opened in _sd_open(). 7280 * "cd" -- cache descriptor number whose kstats we wish to add 7281 * returns: 0 on success, -1 on failure 7282 */ 7283 static int 7284 cd_kstat_add(int cd) 7285 { 7286 char name[KSTAT_STRLEN]; 7287 7288 if (cd < 0 || cd >= sdbc_max_devs) { 7289 cmn_err(CE_WARN, "!invalid cache descriptor: %d", cd); 7290 return (-1); 7291 } 7292 7293 /* create a regular kstat for this cache descriptor */ 7294 if (!sdbc_cd_kstats) { 7295 cmn_err(CE_WARN, "!sdbc_cd_kstats not allocated"); 7296 return (-1); 7297 } 7298 7299 (void) snprintf(name, KSTAT_STRLEN, "%s%d", SDBC_KSTAT_CDSTATS, cd); 7300 7301 sdbc_cd_kstats[cd] = kstat_create(SDBC_KSTAT_MODULE, 7302 cd, name, SDBC_KSTAT_CLASS, KSTAT_TYPE_NAMED, 7303 sizeof (sdbc_cd_stats)/sizeof (kstat_named_t), 7304 KSTAT_FLAG_VIRTUAL|KSTAT_FLAG_WRITABLE); 7305 7306 if (sdbc_cd_kstats[cd] != NULL) { 7307 sdbc_cd_kstats[cd]->ks_data = &sdbc_cd_stats; 7308 sdbc_cd_kstats[cd]->ks_update = sdbc_cd_stats_update; 7309 sdbc_cd_kstats[cd]->ks_private = 7310 &_sd_cache_stats->st_shared[cd]; 7311 kstat_install(sdbc_cd_kstats[cd]); 7312 } else { 7313 cmn_err(CE_WARN, "!cdstats %d kstat allocation failed", cd); 7314 } 7315 7316 /* create an I/O kstat for this cache descriptor */ 7317 if (!sdbc_cd_io_kstats) { 7318 cmn_err(CE_WARN, "!sdbc_cd_io_kstats not allocated"); 7319 return (-1); 7320 } 7321 7322 (void) snprintf(name, KSTAT_STRLEN, "%s%d", SDBC_IOKSTAT_CDSTATS, cd); 7323 7324 sdbc_cd_io_kstats[cd] = kstat_create( 7325 SDBC_KSTAT_MODULE, cd, name, "disk", KSTAT_TYPE_IO, 1, 0); 7326 7327 if (sdbc_cd_io_kstats[cd]) { 7328 if (!sdbc_cd_io_kstats_mutexes) { 7329 cmn_err(CE_WARN, "!sdbc_cd_io_kstats_mutexes not " 7330 "allocated"); 7331 return (-1); 7332 } 7333 7334 mutex_init(&sdbc_cd_io_kstats_mutexes[cd], NULL, 7335 MUTEX_DRIVER, NULL); 7336 7337 sdbc_cd_io_kstats[cd]->ks_lock = &sdbc_cd_io_kstats_mutexes[cd]; 7338 7339 kstat_install(sdbc_cd_io_kstats[cd]); 7340 7341 } else { 7342 cmn_err(CE_WARN, "!sdbc cd %d io kstat allocation failed", cd); 7343 } 7344 7345 return (0); 7346 } 7347 7348 /* 7349 * cd_kstat_remove 7350 * 7351 * Uninstalls all kstats and associated infrastructure (mutex, buffer), 7352 * associated with a particular cache descriptor. This function is called 7353 * when the cache descriptor is closed in _sd_close(). 7354 * "cd" -- cache descriptor number whose kstats we wish to remove 7355 * returns: 0 on success, -1 on failure 7356 */ 7357 static int 7358 cd_kstat_remove(int cd) 7359 { 7360 if (cd < 0 || cd >= sdbc_max_devs) { 7361 cmn_err(CE_WARN, "!invalid cache descriptor: %d", cd); 7362 return (-1); 7363 } 7364 7365 /* delete the regular kstat corresponding to this cache descriptor */ 7366 if (sdbc_cd_kstats && sdbc_cd_kstats[cd]) { 7367 kstat_delete(sdbc_cd_kstats[cd]); 7368 sdbc_cd_kstats[cd] = NULL; 7369 } 7370 7371 /* delete the I/O kstat corresponding to this cache descriptor */ 7372 if (sdbc_cd_io_kstats && sdbc_cd_io_kstats[cd]) { 7373 kstat_delete(sdbc_cd_io_kstats[cd]); 7374 sdbc_cd_io_kstats[cd] = NULL; 7375 7376 if (sdbc_cd_io_kstats_mutexes) { 7377 /* destroy the mutex associated with this I/O kstat */ 7378 mutex_destroy(&sdbc_cd_io_kstats_mutexes[cd]); 7379 } 7380 } 7381 7382 return (0); 7383 } 7384 7385 #ifdef DEBUG 7386 /* 7387 * kstat update 7388 */ 7389 int 7390 sdbc_dynmem_kstat_update_dm(kstat_t *ksp, int rw) 7391 { 7392 sdbc_dynmem_dm_t *sdbc_dynmem; 7393 _dm_process_vars_t *process_vars; 7394 _dm_process_vars_t local_dm_process_vars; 7395 7396 simplect_dm++; 7397 7398 sdbc_dynmem = (sdbc_dynmem_dm_t *)(ksp->ks_data); 7399 7400 /* global dynmem_processing_dm */ 7401 process_vars = (_dm_process_vars_t *)(ksp->ks_private); 7402 7403 if (rw == KSTAT_WRITE) { 7404 simplect_dm = sdbc_dynmem->ci_sdbc_simplect.value.ul; 7405 local_dm_process_vars.monitor_dynmem_process = 7406 sdbc_dynmem->ci_sdbc_monitor_dynmem.value.ul; 7407 local_dm_process_vars.max_dyn_list = 7408 sdbc_dynmem->ci_sdbc_max_dyn_list.value.ul; 7409 local_dm_process_vars.cache_aging_ct1 = 7410 sdbc_dynmem->ci_sdbc_cache_aging_ct1.value.ul; 7411 local_dm_process_vars.cache_aging_ct2 = 7412 sdbc_dynmem->ci_sdbc_cache_aging_ct2.value.ul; 7413 local_dm_process_vars.cache_aging_ct3 = 7414 sdbc_dynmem->ci_sdbc_cache_aging_ct3.value.ul; 7415 local_dm_process_vars.cache_aging_sec1 = 7416 sdbc_dynmem->ci_sdbc_cache_aging_sec1.value.ul; 7417 local_dm_process_vars.cache_aging_sec2 = 7418 sdbc_dynmem->ci_sdbc_cache_aging_sec2.value.ul; 7419 local_dm_process_vars.cache_aging_sec3 = 7420 sdbc_dynmem->ci_sdbc_cache_aging_sec3.value.ul; 7421 local_dm_process_vars.cache_aging_pcnt1 = 7422 sdbc_dynmem->ci_sdbc_cache_aging_pcnt1.value.ul; 7423 local_dm_process_vars.cache_aging_pcnt2 = 7424 sdbc_dynmem->ci_sdbc_cache_aging_pcnt2.value.ul; 7425 local_dm_process_vars.max_holds_pcnt = 7426 sdbc_dynmem->ci_sdbc_max_holds_pcnt.value.ul; 7427 local_dm_process_vars.process_directive = 7428 sdbc_dynmem->ci_sdbc_process_directive.value.ul; 7429 (void) sdbc_edit_xfer_process_vars_dm(&local_dm_process_vars); 7430 7431 if (process_vars->process_directive & WAKE_DEALLOC_THREAD_DM) { 7432 process_vars->process_directive &= 7433 ~WAKE_DEALLOC_THREAD_DM; 7434 mutex_enter(&dynmem_processing_dm.thread_dm_lock); 7435 cv_broadcast(&dynmem_processing_dm.thread_dm_cv); 7436 mutex_exit(&dynmem_processing_dm.thread_dm_lock); 7437 } 7438 7439 return (0); 7440 } 7441 7442 /* default to READ */ 7443 sdbc_dynmem->ci_sdbc_simplect.value.ul = simplect_dm; 7444 sdbc_dynmem->ci_sdbc_monitor_dynmem.value.ul = 7445 process_vars->monitor_dynmem_process; 7446 sdbc_dynmem->ci_sdbc_max_dyn_list.value.ul = 7447 process_vars->max_dyn_list; 7448 sdbc_dynmem->ci_sdbc_cache_aging_ct1.value.ul = 7449 process_vars->cache_aging_ct1; 7450 sdbc_dynmem->ci_sdbc_cache_aging_ct2.value.ul = 7451 process_vars->cache_aging_ct2; 7452 sdbc_dynmem->ci_sdbc_cache_aging_ct3.value.ul = 7453 process_vars->cache_aging_ct3; 7454 sdbc_dynmem->ci_sdbc_cache_aging_sec1.value.ul = 7455 process_vars->cache_aging_sec1; 7456 sdbc_dynmem->ci_sdbc_cache_aging_sec2.value.ul = 7457 process_vars->cache_aging_sec2; 7458 sdbc_dynmem->ci_sdbc_cache_aging_sec3.value.ul = 7459 process_vars->cache_aging_sec3; 7460 sdbc_dynmem->ci_sdbc_cache_aging_pcnt1.value.ul = 7461 process_vars->cache_aging_pcnt1; 7462 sdbc_dynmem->ci_sdbc_cache_aging_pcnt2.value.ul = 7463 process_vars->cache_aging_pcnt2; 7464 sdbc_dynmem->ci_sdbc_max_holds_pcnt.value.ul = 7465 process_vars->max_holds_pcnt; 7466 sdbc_dynmem->ci_sdbc_process_directive.value.ul = 7467 process_vars->process_directive; 7468 7469 sdbc_dynmem->ci_sdbc_alloc_ct.value.ul = process_vars->alloc_ct; 7470 sdbc_dynmem->ci_sdbc_dealloc_ct.value.ul = process_vars->dealloc_ct; 7471 sdbc_dynmem->ci_sdbc_history.value.ul = process_vars->history; 7472 sdbc_dynmem->ci_sdbc_nodatas.value.ul = process_vars->nodatas; 7473 sdbc_dynmem->ci_sdbc_candidates.value.ul = process_vars->candidates; 7474 sdbc_dynmem->ci_sdbc_deallocs.value.ul = process_vars->deallocs; 7475 sdbc_dynmem->ci_sdbc_hosts.value.ul = process_vars->hosts; 7476 sdbc_dynmem->ci_sdbc_pests.value.ul = process_vars->pests; 7477 sdbc_dynmem->ci_sdbc_metas.value.ul = process_vars->metas; 7478 sdbc_dynmem->ci_sdbc_holds.value.ul = process_vars->holds; 7479 sdbc_dynmem->ci_sdbc_others.value.ul = process_vars->others; 7480 sdbc_dynmem->ci_sdbc_notavail.value.ul = process_vars->notavail; 7481 7482 return (0); 7483 } 7484 #endif