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 https://opensource.org/licenses/CDDL-1.0. 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 * Copyright (c) 2012 Cyril Plisko. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2013, 2017 by Delphix. All rights reserved. 29 */ 30 31 /* 32 * Print intent log header and statistics. 33 */ 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <ctype.h> 38 #include <sys/zfs_context.h> 39 #include <sys/spa.h> 40 #include <sys/dmu.h> 41 #include <sys/stat.h> 42 #include <sys/resource.h> 43 #include <sys/zil.h> 44 #include <sys/zil_impl.h> 45 #include <sys/spa_impl.h> 46 #include <sys/abd.h> 47 48 #include "zdb.h" 49 50 extern uint8_t dump_opt[256]; 51 52 static char tab_prefix[4] = "\t\t\t"; 53 54 static void 55 print_log_bp(const blkptr_t *bp, const char *prefix) 56 { 57 char blkbuf[BP_SPRINTF_LEN]; 58 59 snprintf_blkptr(blkbuf, sizeof (blkbuf), bp); 60 (void) printf("%s%s\n", prefix, blkbuf); 61 } 62 63 static void 64 zil_prt_rec_create(zilog_t *zilog, int txtype, const void *arg) 65 { 66 (void) zilog; 67 const lr_create_t *lr = arg; 68 time_t crtime = lr->lr_crtime[0]; 69 char *name, *link; 70 lr_attr_t *lrattr; 71 72 name = (char *)(lr + 1); 73 74 if (lr->lr_common.lrc_txtype == TX_CREATE_ATTR || 75 lr->lr_common.lrc_txtype == TX_MKDIR_ATTR) { 76 lrattr = (lr_attr_t *)(lr + 1); 77 name += ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); 78 } 79 80 if (txtype == TX_SYMLINK) { 81 link = name + strlen(name) + 1; 82 (void) printf("%s%s -> %s\n", tab_prefix, name, link); 83 } else if (txtype != TX_MKXATTR) { 84 (void) printf("%s%s\n", tab_prefix, name); 85 } 86 87 (void) printf("%s%s", tab_prefix, ctime(&crtime)); 88 (void) printf("%sdoid %llu, foid %llu, slots %llu, mode %llo\n", 89 tab_prefix, (u_longlong_t)lr->lr_doid, 90 (u_longlong_t)LR_FOID_GET_OBJ(lr->lr_foid), 91 (u_longlong_t)LR_FOID_GET_SLOTS(lr->lr_foid), 92 (longlong_t)lr->lr_mode); 93 (void) printf("%suid %llu, gid %llu, gen %llu, rdev 0x%llx\n", 94 tab_prefix, 95 (u_longlong_t)lr->lr_uid, (u_longlong_t)lr->lr_gid, 96 (u_longlong_t)lr->lr_gen, (u_longlong_t)lr->lr_rdev); 97 } 98 99 static void 100 zil_prt_rec_remove(zilog_t *zilog, int txtype, const void *arg) 101 { 102 (void) zilog, (void) txtype; 103 const lr_remove_t *lr = arg; 104 105 (void) printf("%sdoid %llu, name %s\n", tab_prefix, 106 (u_longlong_t)lr->lr_doid, (char *)(lr + 1)); 107 } 108 109 static void 110 zil_prt_rec_link(zilog_t *zilog, int txtype, const void *arg) 111 { 112 (void) zilog, (void) txtype; 113 const lr_link_t *lr = arg; 114 115 (void) printf("%sdoid %llu, link_obj %llu, name %s\n", tab_prefix, 116 (u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_link_obj, 117 (char *)(lr + 1)); 118 } 119 120 static void 121 zil_prt_rec_rename(zilog_t *zilog, int txtype, const void *arg) 122 { 123 (void) zilog, (void) txtype; 124 const lr_rename_t *lr = arg; 125 char *snm = (char *)(lr + 1); 126 char *tnm = snm + strlen(snm) + 1; 127 128 (void) printf("%ssdoid %llu, tdoid %llu\n", tab_prefix, 129 (u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid); 130 (void) printf("%ssrc %s tgt %s\n", tab_prefix, snm, tnm); 131 switch (txtype) { 132 case TX_RENAME_EXCHANGE: 133 (void) printf("%sflags RENAME_EXCHANGE\n", tab_prefix); 134 break; 135 case TX_RENAME_WHITEOUT: 136 (void) printf("%sflags RENAME_WHITEOUT\n", tab_prefix); 137 break; 138 } 139 } 140 141 static int 142 zil_prt_rec_write_cb(void *data, size_t len, void *unused) 143 { 144 (void) unused; 145 char *cdata = data; 146 147 for (size_t i = 0; i < len; i++) { 148 if (isprint(*cdata)) 149 (void) printf("%c ", *cdata); 150 else 151 (void) printf("%2X", *cdata); 152 cdata++; 153 } 154 return (0); 155 } 156 157 static void 158 zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg) 159 { 160 const lr_write_t *lr = arg; 161 abd_t *data; 162 const blkptr_t *bp = &lr->lr_blkptr; 163 zbookmark_phys_t zb; 164 int verbose = MAX(dump_opt['d'], dump_opt['i']); 165 int error; 166 167 (void) printf("%sfoid %llu, offset %llx, length %llx\n", tab_prefix, 168 (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset, 169 (u_longlong_t)lr->lr_length); 170 171 if (txtype == TX_WRITE2 || verbose < 4) 172 return; 173 174 if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) { 175 (void) printf("%shas blkptr, %s\n", tab_prefix, 176 !BP_IS_HOLE(bp) && BP_GET_LOGICAL_BIRTH(bp) >= 177 spa_min_claim_txg(zilog->zl_spa) ? 178 "will claim" : "won't claim"); 179 print_log_bp(bp, tab_prefix); 180 181 if (verbose < 5) 182 return; 183 if (BP_IS_HOLE(bp)) { 184 (void) printf("\t\t\tLSIZE 0x%llx\n", 185 (u_longlong_t)BP_GET_LSIZE(bp)); 186 (void) printf("%s<hole>\n", tab_prefix); 187 return; 188 } 189 if (BP_GET_LOGICAL_BIRTH(bp) < zilog->zl_header->zh_claim_txg) { 190 (void) printf("%s<block already committed>\n", 191 tab_prefix); 192 return; 193 } 194 195 ASSERT3U(BP_GET_LSIZE(bp), !=, 0); 196 SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os), 197 lr->lr_foid, ZB_ZIL_LEVEL, 198 lr->lr_offset / BP_GET_LSIZE(bp)); 199 200 data = abd_alloc(BP_GET_LSIZE(bp), B_FALSE); 201 error = zio_wait(zio_read(NULL, zilog->zl_spa, 202 bp, data, BP_GET_LSIZE(bp), NULL, NULL, 203 ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &zb)); 204 if (error) 205 goto out; 206 } else { 207 if (verbose < 5) 208 return; 209 210 /* data is stored after the end of the lr_write record */ 211 data = abd_alloc(lr->lr_length, B_FALSE); 212 abd_copy_from_buf(data, lr + 1, lr->lr_length); 213 } 214 215 (void) printf("%s", tab_prefix); 216 (void) abd_iterate_func(data, 217 0, MIN(lr->lr_length, (verbose < 6 ? 20 : SPA_MAXBLOCKSIZE)), 218 zil_prt_rec_write_cb, NULL); 219 (void) printf("\n"); 220 221 out: 222 abd_free(data); 223 } 224 225 static void 226 zil_prt_rec_write_enc(zilog_t *zilog, int txtype, const void *arg) 227 { 228 (void) txtype; 229 const lr_write_t *lr = arg; 230 const blkptr_t *bp = &lr->lr_blkptr; 231 int verbose = MAX(dump_opt['d'], dump_opt['i']); 232 233 (void) printf("%s(encrypted)\n", tab_prefix); 234 235 if (verbose < 4) 236 return; 237 238 if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) { 239 (void) printf("%shas blkptr, %s\n", tab_prefix, 240 !BP_IS_HOLE(bp) && BP_GET_LOGICAL_BIRTH(bp) >= 241 spa_min_claim_txg(zilog->zl_spa) ? 242 "will claim" : "won't claim"); 243 print_log_bp(bp, tab_prefix); 244 } 245 } 246 247 static void 248 zil_prt_rec_truncate(zilog_t *zilog, int txtype, const void *arg) 249 { 250 (void) zilog, (void) txtype; 251 const lr_truncate_t *lr = arg; 252 253 (void) printf("%sfoid %llu, offset 0x%llx, length 0x%llx\n", tab_prefix, 254 (u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset, 255 (u_longlong_t)lr->lr_length); 256 } 257 258 static void 259 zil_prt_rec_setattr(zilog_t *zilog, int txtype, const void *arg) 260 { 261 (void) zilog, (void) txtype; 262 const lr_setattr_t *lr = arg; 263 time_t atime = (time_t)lr->lr_atime[0]; 264 time_t mtime = (time_t)lr->lr_mtime[0]; 265 266 (void) printf("%sfoid %llu, mask 0x%llx\n", tab_prefix, 267 (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_mask); 268 269 if (lr->lr_mask & AT_MODE) { 270 (void) printf("%sAT_MODE %llo\n", tab_prefix, 271 (longlong_t)lr->lr_mode); 272 } 273 274 if (lr->lr_mask & AT_UID) { 275 (void) printf("%sAT_UID %llu\n", tab_prefix, 276 (u_longlong_t)lr->lr_uid); 277 } 278 279 if (lr->lr_mask & AT_GID) { 280 (void) printf("%sAT_GID %llu\n", tab_prefix, 281 (u_longlong_t)lr->lr_gid); 282 } 283 284 if (lr->lr_mask & AT_SIZE) { 285 (void) printf("%sAT_SIZE %llu\n", tab_prefix, 286 (u_longlong_t)lr->lr_size); 287 } 288 289 if (lr->lr_mask & AT_ATIME) { 290 (void) printf("%sAT_ATIME %llu.%09llu %s", tab_prefix, 291 (u_longlong_t)lr->lr_atime[0], 292 (u_longlong_t)lr->lr_atime[1], 293 ctime(&atime)); 294 } 295 296 if (lr->lr_mask & AT_MTIME) { 297 (void) printf("%sAT_MTIME %llu.%09llu %s", tab_prefix, 298 (u_longlong_t)lr->lr_mtime[0], 299 (u_longlong_t)lr->lr_mtime[1], 300 ctime(&mtime)); 301 } 302 } 303 304 static void 305 zil_prt_rec_setsaxattr(zilog_t *zilog, int txtype, const void *arg) 306 { 307 (void) zilog, (void) txtype; 308 const lr_setsaxattr_t *lr = arg; 309 310 char *name = (char *)(lr + 1); 311 (void) printf("%sfoid %llu\n", tab_prefix, 312 (u_longlong_t)lr->lr_foid); 313 314 (void) printf("%sXAT_NAME %s\n", tab_prefix, name); 315 if (lr->lr_size == 0) { 316 (void) printf("%sXAT_VALUE NULL\n", tab_prefix); 317 } else { 318 (void) printf("%sXAT_VALUE ", tab_prefix); 319 char *val = name + (strlen(name) + 1); 320 for (int i = 0; i < lr->lr_size; i++) { 321 (void) printf("%c", *val); 322 val++; 323 } 324 } 325 } 326 327 static void 328 zil_prt_rec_acl(zilog_t *zilog, int txtype, const void *arg) 329 { 330 (void) zilog, (void) txtype; 331 const lr_acl_t *lr = arg; 332 333 (void) printf("%sfoid %llu, aclcnt %llu\n", tab_prefix, 334 (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_aclcnt); 335 } 336 337 static void 338 zil_prt_rec_clone_range(zilog_t *zilog, int txtype, const void *arg) 339 { 340 (void) zilog, (void) txtype; 341 const lr_clone_range_t *lr = arg; 342 int verbose = MAX(dump_opt['d'], dump_opt['i']); 343 344 (void) printf("%sfoid %llu, offset %llx, length %llx, blksize %llx\n", 345 tab_prefix, (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset, 346 (u_longlong_t)lr->lr_length, (u_longlong_t)lr->lr_blksz); 347 348 if (verbose < 4) 349 return; 350 351 for (unsigned int i = 0; i < lr->lr_nbps; i++) { 352 (void) printf("%s[%u/%llu] ", tab_prefix, i + 1, 353 (u_longlong_t)lr->lr_nbps); 354 print_log_bp(&lr->lr_bps[i], ""); 355 } 356 } 357 358 static void 359 zil_prt_rec_clone_range_enc(zilog_t *zilog, int txtype, const void *arg) 360 { 361 (void) zilog, (void) txtype; 362 const lr_clone_range_t *lr = arg; 363 int verbose = MAX(dump_opt['d'], dump_opt['i']); 364 365 (void) printf("%s(encrypted)\n", tab_prefix); 366 367 if (verbose < 4) 368 return; 369 370 for (unsigned int i = 0; i < lr->lr_nbps; i++) { 371 (void) printf("%s[%u/%llu] ", tab_prefix, i + 1, 372 (u_longlong_t)lr->lr_nbps); 373 print_log_bp(&lr->lr_bps[i], ""); 374 } 375 } 376 377 typedef void (*zil_prt_rec_func_t)(zilog_t *, int, const void *); 378 typedef struct zil_rec_info { 379 zil_prt_rec_func_t zri_print; 380 zil_prt_rec_func_t zri_print_enc; 381 const char *zri_name; 382 uint64_t zri_count; 383 } zil_rec_info_t; 384 385 static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = { 386 {.zri_print = NULL, .zri_name = "Total "}, 387 {.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE "}, 388 {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR "}, 389 {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKXATTR "}, 390 {.zri_print = zil_prt_rec_create, .zri_name = "TX_SYMLINK "}, 391 {.zri_print = zil_prt_rec_remove, .zri_name = "TX_REMOVE "}, 392 {.zri_print = zil_prt_rec_remove, .zri_name = "TX_RMDIR "}, 393 {.zri_print = zil_prt_rec_link, .zri_name = "TX_LINK "}, 394 {.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME "}, 395 {.zri_print = zil_prt_rec_write, 396 .zri_print_enc = zil_prt_rec_write_enc, 397 .zri_name = "TX_WRITE "}, 398 {.zri_print = zil_prt_rec_truncate, .zri_name = "TX_TRUNCATE "}, 399 {.zri_print = zil_prt_rec_setattr, .zri_name = "TX_SETATTR "}, 400 {.zri_print = zil_prt_rec_acl, .zri_name = "TX_ACL_V0 "}, 401 {.zri_print = zil_prt_rec_acl, .zri_name = "TX_ACL_ACL "}, 402 {.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE_ACL "}, 403 {.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE_ATTR "}, 404 {.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE_ACL_ATTR "}, 405 {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ACL "}, 406 {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ATTR "}, 407 {.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ACL_ATTR "}, 408 {.zri_print = zil_prt_rec_write, .zri_name = "TX_WRITE2 "}, 409 {.zri_print = zil_prt_rec_setsaxattr, 410 .zri_name = "TX_SETSAXATTR "}, 411 {.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME_EXCHANGE "}, 412 {.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME_WHITEOUT "}, 413 {.zri_print = zil_prt_rec_clone_range, 414 .zri_print_enc = zil_prt_rec_clone_range_enc, 415 .zri_name = "TX_CLONE_RANGE "}, 416 }; 417 418 static int 419 print_log_record(zilog_t *zilog, const lr_t *lr, void *arg, uint64_t claim_txg) 420 { 421 (void) arg, (void) claim_txg; 422 int txtype; 423 int verbose = MAX(dump_opt['d'], dump_opt['i']); 424 425 /* reduce size of txtype to strip off TX_CI bit */ 426 txtype = lr->lrc_txtype; 427 428 ASSERT(txtype != 0 && (uint_t)txtype < TX_MAX_TYPE); 429 ASSERT(lr->lrc_txg); 430 431 (void) printf("\t\t%s%s len %6llu, txg %llu, seq %llu\n", 432 (lr->lrc_txtype & TX_CI) ? "CI-" : "", 433 zil_rec_info[txtype].zri_name, 434 (u_longlong_t)lr->lrc_reclen, 435 (u_longlong_t)lr->lrc_txg, 436 (u_longlong_t)lr->lrc_seq); 437 438 if (txtype && verbose >= 3) { 439 if (!zilog->zl_os->os_encrypted) { 440 zil_rec_info[txtype].zri_print(zilog, txtype, lr); 441 } else if (zil_rec_info[txtype].zri_print_enc) { 442 zil_rec_info[txtype].zri_print_enc(zilog, txtype, lr); 443 } else { 444 (void) printf("%s(encrypted)\n", tab_prefix); 445 } 446 } 447 448 zil_rec_info[txtype].zri_count++; 449 zil_rec_info[0].zri_count++; 450 451 return (0); 452 } 453 454 static int 455 print_log_block(zilog_t *zilog, const blkptr_t *bp, void *arg, 456 uint64_t claim_txg) 457 { 458 (void) arg; 459 char blkbuf[BP_SPRINTF_LEN + 10]; 460 int verbose = MAX(dump_opt['d'], dump_opt['i']); 461 const char *claim; 462 463 if (verbose <= 3) 464 return (0); 465 466 if (verbose >= 5) { 467 (void) strcpy(blkbuf, ", "); 468 snprintf_blkptr(blkbuf + strlen(blkbuf), 469 sizeof (blkbuf) - strlen(blkbuf), bp); 470 } else { 471 blkbuf[0] = '\0'; 472 } 473 474 if (claim_txg != 0) 475 claim = "already claimed"; 476 else if (BP_GET_LOGICAL_BIRTH(bp) >= spa_min_claim_txg(zilog->zl_spa)) 477 claim = "will claim"; 478 else 479 claim = "won't claim"; 480 481 (void) printf("\tBlock seqno %llu, %s%s\n", 482 (u_longlong_t)bp->blk_cksum.zc_word[ZIL_ZC_SEQ], claim, blkbuf); 483 484 return (0); 485 } 486 487 static void 488 print_log_stats(int verbose) 489 { 490 unsigned i, w, p10; 491 492 if (verbose > 3) 493 (void) printf("\n"); 494 495 if (zil_rec_info[0].zri_count == 0) 496 return; 497 498 for (w = 1, p10 = 10; zil_rec_info[0].zri_count >= p10; p10 *= 10) 499 w++; 500 501 for (i = 0; i < TX_MAX_TYPE; i++) 502 if (zil_rec_info[i].zri_count || verbose >= 3) 503 (void) printf("\t\t%s %*llu\n", 504 zil_rec_info[i].zri_name, w, 505 (u_longlong_t)zil_rec_info[i].zri_count); 506 (void) printf("\n"); 507 } 508 509 void 510 dump_intent_log(zilog_t *zilog) 511 { 512 const zil_header_t *zh = zilog->zl_header; 513 int verbose = MAX(dump_opt['d'], dump_opt['i']); 514 int i; 515 516 if (BP_IS_HOLE(&zh->zh_log) || verbose < 1) 517 return; 518 519 (void) printf("\n ZIL header: claim_txg %llu, " 520 "claim_blk_seq %llu, claim_lr_seq %llu", 521 (u_longlong_t)zh->zh_claim_txg, 522 (u_longlong_t)zh->zh_claim_blk_seq, 523 (u_longlong_t)zh->zh_claim_lr_seq); 524 (void) printf(" replay_seq %llu, flags 0x%llx\n", 525 (u_longlong_t)zh->zh_replay_seq, (u_longlong_t)zh->zh_flags); 526 527 for (i = 0; i < TX_MAX_TYPE; i++) 528 zil_rec_info[i].zri_count = 0; 529 530 /* see comment in zil_claim() or zil_check_log_chain() */ 531 if (zilog->zl_spa->spa_uberblock.ub_checkpoint_txg != 0 && 532 zh->zh_claim_txg == 0) 533 return; 534 535 if (verbose >= 2) { 536 (void) printf("\n"); 537 (void) zil_parse(zilog, print_log_block, print_log_record, NULL, 538 zh->zh_claim_txg, B_FALSE); 539 print_log_stats(verbose); 540 } 541 } 542