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