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 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/systm.h> 28 #include <sys/types.h> 29 #include <sys/vnode.h> 30 #include <sys/buf.h> 31 #include <sys/ddi.h> 32 #include <sys/errno.h> 33 #include <sys/sysmacros.h> 34 #include <sys/debug.h> 35 #include <sys/kmem.h> 36 #include <sys/conf.h> 37 #include <sys/proc.h> 38 #include <sys/cmn_err.h> 39 #include <sys/fs/ufs_inode.h> 40 #include <sys/fs/ufs_filio.h> 41 #include <sys/fs/ufs_log.h> 42 43 44 #ifdef DEBUG 45 46 /* 47 * DEBUG ROUTINES 48 * THESE ROUTINES ARE ONLY USED WHEN ASSERTS ARE ENABLED 49 */ 50 51 static kmutex_t toptracelock; 52 static int toptraceindex; 53 int toptracemax = 1024; /* global so it can be set */ 54 struct toptrace { 55 enum delta_type dtyp; 56 kthread_t *thread; 57 dev_t dev; 58 long arg2; 59 long arg3; 60 long long arg1; 61 } *toptrace; 62 63 static void 64 top_trace(enum delta_type dtyp, dev_t dev, long long arg1, long arg2, long arg3) 65 { 66 if (toptrace == NULL) { 67 toptraceindex = 0; 68 toptrace = kmem_zalloc((size_t) 69 (sizeof (struct toptrace) * toptracemax), KM_SLEEP); 70 } 71 mutex_enter(&toptracelock); 72 toptrace[toptraceindex].dtyp = dtyp; 73 toptrace[toptraceindex].thread = curthread; 74 toptrace[toptraceindex].dev = dev; 75 toptrace[toptraceindex].arg1 = arg1; 76 toptrace[toptraceindex].arg2 = arg2; 77 toptrace[toptraceindex].arg3 = arg3; 78 if (++toptraceindex == toptracemax) 79 toptraceindex = 0; 80 else { 81 toptrace[toptraceindex].dtyp = (enum delta_type)-1; 82 toptrace[toptraceindex].thread = (kthread_t *)-1; 83 toptrace[toptraceindex].dev = (dev_t)-1; 84 toptrace[toptraceindex].arg1 = -1; 85 toptrace[toptraceindex].arg2 = -1; 86 } 87 88 mutex_exit(&toptracelock); 89 } 90 91 /* 92 * add a range into the metadata map 93 */ 94 void 95 top_mataadd(ufsvfs_t *ufsvfsp, offset_t mof, off_t nb) 96 { 97 ml_unit_t *ul = ufsvfsp->vfs_log; 98 99 ASSERT(ufsvfsp->vfs_dev == ul->un_dev); 100 deltamap_add(ul->un_matamap, mof, nb, 0, 0, 0, NULL); 101 } 102 103 /* 104 * delete a range from the metadata map 105 */ 106 void 107 top_matadel(ufsvfs_t *ufsvfsp, offset_t mof, off_t nb) 108 { 109 ml_unit_t *ul = ufsvfsp->vfs_log; 110 111 ASSERT(ufsvfsp->vfs_dev == ul->un_dev); 112 ASSERT(!matamap_overlap(ul->un_deltamap, mof, nb)); 113 deltamap_del(ul->un_matamap, mof, nb); 114 } 115 116 /* 117 * clear the entries from the metadata map 118 */ 119 void 120 top_mataclr(ufsvfs_t *ufsvfsp) 121 { 122 ml_unit_t *ul = ufsvfsp->vfs_log; 123 124 ASSERT(ufsvfsp->vfs_dev == ul->un_dev); 125 map_free_entries(ul->un_matamap); 126 map_free_entries(ul->un_deltamap); 127 } 128 129 int 130 top_begin_debug(ml_unit_t *ul, top_t topid, ulong_t size) 131 { 132 threadtrans_t *tp; 133 134 if (ul->un_debug & MT_TRACE) 135 top_trace(DT_BOT, ul->un_dev, 136 (long long)topid, (long)size, (long)0); 137 138 ASSERT(curthread->t_flag & T_DONTBLOCK); 139 140 tp = tsd_get(topkey); 141 if (tp == NULL) { 142 tp = kmem_zalloc(sizeof (threadtrans_t), KM_SLEEP); 143 (void) tsd_set(topkey, tp); 144 } 145 tp->topid = topid; 146 tp->esize = size; 147 tp->rsize = 0; 148 tp->dev = ul->un_dev; 149 return (1); 150 } 151 152 int 153 top_end_debug(ml_unit_t *ul, mt_map_t *mtm, top_t topid, ulong_t size) 154 { 155 threadtrans_t *tp; 156 157 ASSERT(curthread->t_flag & T_DONTBLOCK); 158 159 ASSERT((tp = (threadtrans_t *)tsd_get(topkey)) != NULL); 160 161 ASSERT((tp->dev == ul->un_dev) && (tp->topid == topid) && 162 (tp->esize == size)); 163 164 ASSERT(((ul->un_debug & MT_SIZE) == 0) || (tp->rsize <= tp->esize)); 165 166 mtm->mtm_tops->mtm_top_num[topid]++; 167 mtm->mtm_tops->mtm_top_size_etot[topid] += tp->esize; 168 mtm->mtm_tops->mtm_top_size_rtot[topid] += tp->rsize; 169 170 if (tp->rsize > mtm->mtm_tops->mtm_top_size_max[topid]) 171 mtm->mtm_tops->mtm_top_size_max[topid] = tp->rsize; 172 if (mtm->mtm_tops->mtm_top_size_min[topid] == 0) 173 mtm->mtm_tops->mtm_top_size_min[topid] = 174 tp->rsize; 175 else 176 if (tp->rsize < mtm->mtm_tops->mtm_top_size_min[topid]) 177 mtm->mtm_tops->mtm_top_size_min[topid] = 178 tp->rsize; 179 180 if (ul->un_debug & MT_TRACE) 181 top_trace(DT_EOT, ul->un_dev, (long long)topid, 182 (long)tp->rsize, (long)0); 183 184 return (1); 185 } 186 187 int 188 top_delta_debug( 189 ml_unit_t *ul, 190 offset_t mof, 191 off_t nb, 192 delta_t dtyp) 193 { 194 struct threadtrans *tp; 195 196 ASSERT(curthread->t_flag & T_DONTBLOCK); 197 198 /* 199 * check for delta contained fully within matamap 200 */ 201 ASSERT((ul->un_matamap == NULL) || 202 matamap_within(ul->un_matamap, mof, nb)); 203 204 /* 205 * maintain transaction info 206 */ 207 if (ul->un_debug & MT_TRANSACT) 208 ul->un_logmap->mtm_tops->mtm_delta_num[dtyp]++; 209 210 /* 211 * check transaction stuff 212 */ 213 if (ul->un_debug & MT_TRANSACT) { 214 tp = (struct threadtrans *)tsd_get(topkey); 215 ASSERT(tp); 216 switch (dtyp) { 217 case DT_CANCEL: 218 case DT_ABZERO: 219 if (!matamap_within(ul->un_deltamap, mof, nb)) 220 tp->rsize += sizeof (struct delta); 221 break; 222 default: 223 if (!matamap_within(ul->un_deltamap, mof, nb)) 224 tp->rsize += nb + sizeof (struct delta); 225 break; 226 } 227 } else 228 return (1); 229 230 if (ul->un_debug & MT_TRACE) 231 top_trace(dtyp, ul->un_dev, mof, (long)nb, (long)0); 232 233 return (1); 234 } 235 236 int 237 top_roll_debug(ml_unit_t *ul) 238 { 239 logmap_roll_dev(ul); 240 return (1); 241 } 242 243 int 244 top_init_debug(void) 245 { 246 mutex_init(&toptracelock, NULL, MUTEX_DEFAULT, NULL); 247 return (1); 248 } 249 250 struct topstats_link { 251 struct topstats_link *ts_next; 252 dev_t ts_dev; 253 struct topstats ts_stats; 254 }; 255 struct topstats_link *topstats_anchor = NULL; 256 257 /* 258 * DEBUG ROUTINES 259 * from debug portion of *_map.c 260 */ 261 /* 262 * scan test support 263 */ 264 int 265 logmap_logscan_debug(mt_map_t *mtm, mapentry_t *age) 266 { 267 mapentry_t *me; 268 ml_unit_t *ul; 269 off_t head, trimroll, lof; 270 271 /* 272 * remember location of youngest rolled delta 273 */ 274 mutex_enter(&mtm->mtm_mutex); 275 ul = mtm->mtm_ul; 276 head = ul->un_head_lof; 277 trimroll = mtm->mtm_trimrlof; 278 for (me = age; me; me = me->me_agenext) { 279 lof = me->me_lof; 280 if (trimroll == 0) 281 trimroll = lof; 282 if (lof >= head) { 283 if (trimroll >= head && trimroll <= lof) 284 trimroll = lof; 285 } else { 286 if (trimroll <= lof || trimroll >= head) 287 trimroll = lof; 288 } 289 } 290 mtm->mtm_trimrlof = trimroll; 291 mutex_exit(&mtm->mtm_mutex); 292 return (1); 293 } 294 295 /* 296 * scan test support 297 */ 298 int 299 logmap_logscan_commit_debug(off_t lof, mt_map_t *mtm) 300 { 301 off_t oldtrimc, newtrimc, trimroll; 302 303 trimroll = mtm->mtm_trimrlof; 304 oldtrimc = mtm->mtm_trimclof; 305 newtrimc = mtm->mtm_trimclof = dbtob(btod(lof)); 306 307 /* 308 * can't trim prior to transaction w/rolled delta 309 */ 310 if (trimroll) 311 if (newtrimc >= oldtrimc) { 312 if (trimroll <= newtrimc && trimroll >= oldtrimc) 313 mtm->mtm_trimalof = newtrimc; 314 } else { 315 if (trimroll >= oldtrimc || trimroll <= newtrimc) 316 mtm->mtm_trimalof = newtrimc; 317 } 318 return (1); 319 } 320 321 int 322 logmap_logscan_add_debug(struct delta *dp, mt_map_t *mtm) 323 { 324 if ((dp->d_typ == DT_AB) || (dp->d_typ == DT_INODE)) 325 mtm->mtm_trimalof = mtm->mtm_trimclof; 326 return (1); 327 } 328 329 /* 330 * log-read after log-write 331 */ 332 int 333 map_check_ldl_write(ml_unit_t *ul, caddr_t va, offset_t vamof, mapentry_t *me) 334 { 335 caddr_t bufp; 336 337 ASSERT(me->me_nb); 338 ASSERT((me->me_flags & ME_AGE) == 0); 339 340 /* Alloc a buf */ 341 bufp = kmem_alloc(me->me_nb, KM_SLEEP); 342 343 /* Do the read */ 344 me->me_agenext = NULL; 345 if (ldl_read(ul, bufp, me->me_mof, me->me_nb, me) == 0) { 346 ASSERT(bcmp(bufp, va + (me->me_mof - vamof), me->me_nb) == 0); 347 } 348 349 kmem_free(bufp, me->me_nb); 350 return (1); 351 } 352 353 /* 354 * Cleanup a map struct 355 */ 356 int 357 map_put_debug(mt_map_t *mtm) 358 { 359 struct topstats_link *tsl, **ptsl; 360 361 if (mtm->mtm_tops == NULL) 362 return (1); 363 364 /* Don't free this, cause the next snarf will want it */ 365 if ((lufs_debug & MT_TRANSACT) != 0) 366 return (1); 367 368 ptsl = &topstats_anchor; 369 tsl = topstats_anchor; 370 while (tsl) { 371 if (mtm->mtm_tops == &tsl->ts_stats) { 372 mtm->mtm_tops = NULL; 373 *ptsl = tsl->ts_next; 374 kmem_free(tsl, sizeof (*tsl)); 375 return (1); 376 } 377 ptsl = &tsl->ts_next; 378 tsl = tsl->ts_next; 379 } 380 381 return (1); 382 } 383 384 int 385 map_get_debug(ml_unit_t *ul, mt_map_t *mtm) 386 { 387 struct topstats_link *tsl; 388 389 if ((ul->un_debug & MT_TRANSACT) == 0) 390 return (1); 391 392 if (mtm->mtm_type != logmaptype) 393 return (1); 394 395 tsl = topstats_anchor; 396 while (tsl) { 397 if (tsl->ts_dev == ul->un_dev) { 398 mtm->mtm_tops = &(tsl->ts_stats); 399 return (1); 400 } 401 tsl = tsl->ts_next; 402 } 403 404 tsl = kmem_zalloc(sizeof (*tsl), KM_SLEEP); 405 tsl->ts_dev = ul->un_dev; 406 tsl->ts_next = topstats_anchor; 407 topstats_anchor = tsl; 408 mtm->mtm_tops = &tsl->ts_stats; 409 return (1); 410 } 411 412 /* 413 * check a map's list 414 */ 415 int 416 map_check_linkage(mt_map_t *mtm) 417 { 418 int i; 419 int hashed; 420 int nexted; 421 int preved; 422 int ncancel; 423 mapentry_t *me; 424 off_t olof; 425 off_t firstlof; 426 int wrapped; 427 428 mutex_enter(&mtm->mtm_mutex); 429 430 ASSERT(mtm->mtm_nme >= 0); 431 432 /* 433 * verify the entries on the hash 434 */ 435 hashed = 0; 436 for (i = 0; i < mtm->mtm_nhash; ++i) { 437 for (me = *(mtm->mtm_hash+i); me; me = me->me_hash) { 438 ++hashed; 439 ASSERT(me->me_flags & ME_HASH); 440 ASSERT((me->me_flags & ME_LIST) == 0); 441 } 442 } 443 ASSERT(hashed >= mtm->mtm_nme); 444 /* 445 * verify the doubly linked list of all entries 446 */ 447 nexted = 0; 448 for (me = mtm->mtm_next; me != (mapentry_t *)mtm; me = me->me_next) 449 nexted++; 450 preved = 0; 451 for (me = mtm->mtm_prev; me != (mapentry_t *)mtm; me = me->me_prev) 452 preved++; 453 ASSERT(nexted == preved); 454 ASSERT(nexted == hashed); 455 456 /* 457 * verify the cancel list 458 */ 459 ncancel = 0; 460 for (me = mtm->mtm_cancel; me; me = me->me_cancel) { 461 ++ncancel; 462 ASSERT(me->me_flags & ME_CANCEL); 463 } 464 /* 465 * verify the logmap's log offsets 466 */ 467 if (mtm->mtm_type == logmaptype) { 468 olof = mtm->mtm_next->me_lof; 469 firstlof = olof; 470 wrapped = 0; 471 /* 472 * Make sure to skip any mapentries whose me_lof = 0 473 * and me_type == DT_CANCEL, these are mapentries 474 * in place just to mark user block deletions as not 475 * available for allocate within the same moby transaction 476 * in case we crash before it is comitted. Skip these 477 * entries in the checks below as they are not applicable. 478 */ 479 for (me = mtm->mtm_next->me_next; 480 me != (mapentry_t *)mtm; 481 me = me->me_next) { 482 483 if (me->me_lof == 0 && me->me_dt == DT_CANCEL) 484 continue; 485 if (firstlof == 0) { 486 olof = me->me_lof; 487 firstlof = olof; 488 if (me->me_next != (mapentry_t *)mtm) 489 me = me->me_next; 490 continue; 491 } 492 ASSERT(me->me_lof != olof); 493 494 if (wrapped) { 495 ASSERT(me->me_lof > olof); 496 ASSERT(me->me_lof < firstlof); 497 olof = me->me_lof; 498 continue; 499 } 500 if (me->me_lof < olof) { 501 ASSERT(me->me_lof < firstlof); 502 wrapped = 1; 503 olof = me->me_lof; 504 continue; 505 } 506 ASSERT(me->me_lof > firstlof); 507 ASSERT(me->me_lof < mtm->mtm_ul->un_eol_lof); 508 olof = me->me_lof; 509 } 510 } 511 512 mutex_exit(&mtm->mtm_mutex); 513 return (1); 514 } 515 516 /* 517 * check for overlap 518 */ 519 int 520 matamap_overlap(mt_map_t *mtm, offset_t mof, off_t nb) 521 { 522 off_t hnb; 523 mapentry_t *me; 524 mapentry_t **mep; 525 526 for (hnb = 0; nb; nb -= hnb, mof += hnb) { 527 528 hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF); 529 if (hnb > nb) 530 hnb = nb; 531 /* 532 * search for dup entry 533 */ 534 mep = MAP_HASH(mof, mtm); 535 mutex_enter(&mtm->mtm_mutex); 536 for (me = *mep; me; me = me->me_hash) 537 if (DATAoverlapME(mof, hnb, me)) 538 break; 539 mutex_exit(&mtm->mtm_mutex); 540 541 /* 542 * overlap detected 543 */ 544 if (me) 545 return (1); 546 } 547 return (0); 548 } 549 /* 550 * check for within 551 */ 552 int 553 matamap_within(mt_map_t *mtm, offset_t mof, off_t nb) 554 { 555 off_t hnb; 556 mapentry_t *me; 557 mapentry_t **mep; 558 int scans = 0; 559 int withins = 0; 560 561 for (hnb = 0; nb && scans == withins; nb -= hnb, mof += hnb) { 562 scans++; 563 564 hnb = MAPBLOCKSIZE - (mof & MAPBLOCKOFF); 565 if (hnb > nb) 566 hnb = nb; 567 /* 568 * search for within entry 569 */ 570 mep = MAP_HASH(mof, mtm); 571 mutex_enter(&mtm->mtm_mutex); 572 for (me = *mep; me; me = me->me_hash) 573 if (DATAwithinME(mof, hnb, me)) { 574 withins++; 575 break; 576 } 577 mutex_exit(&mtm->mtm_mutex); 578 } 579 return (scans == withins); 580 } 581 582 int 583 ldl_sethead_debug(ml_unit_t *ul) 584 { 585 mt_map_t *mtm = ul->un_logmap; 586 off_t trimr = mtm->mtm_trimrlof; 587 off_t head = ul->un_head_lof; 588 off_t tail = ul->un_tail_lof; 589 590 if (head <= tail) { 591 if (trimr < head || trimr >= tail) 592 mtm->mtm_trimrlof = 0; 593 } else { 594 if (trimr >= tail && trimr < head) 595 mtm->mtm_trimrlof = 0; 596 } 597 return (1); 598 } 599 600 int 601 lufs_initialize_debug(ml_odunit_t *ud) 602 { 603 ud->od_debug = lufs_debug; 604 return (1); 605 } 606 607 #endif /* DEBUG */ 608 609 /* 610 * lufs_debug controls the debug level for TSufs, and is only used 611 * for a debug kernel. It's referenced by ufs_ioctl() and so is 612 * not under #ifdef DEBUG compilation. 613 */ 614 uint_t lufs_debug; 615