1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Routines for cachefs logging. 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <stddef.h> 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <errno.h> 39 #include <sys/stat.h> 40 #include <fcntl.h> 41 #include <unistd.h> 42 #include <libintl.h> 43 #include <time.h> 44 #include <string.h> 45 #include <sys/fs/cachefs_fs.h> 46 #include <sys/fs/cachefs_log.h> 47 #include <malloc.h> 48 #include <limits.h> 49 #include "stats.h" 50 #include <assert.h> 51 52 /* forward declarations of statics */ 53 static kstat_t *stats_log_kstat_read(stats_cookie_t *); 54 static char *stats_log_fmtfid(cfs_fid_t *); 55 static bool_t stats_xdr_loghead(XDR *, struct cachefs_log_logfile_header *); 56 static int stats_log_fi_comp(const void *a, const void *b); 57 58 int 59 stats_log_kernel_setname(stats_cookie_t *st, char *path) 60 { 61 int error = 0; 62 kstat_t *log; 63 cachefs_log_control_t *lc; 64 int exists = 0; 65 66 assert(stats_good(st)); 67 68 if ((log = stats_log_kstat_read(st)) == NULL) { 69 error = stats_errno(st); 70 goto out; 71 } 72 73 lc = (cachefs_log_control_t *)log->ks_data; 74 75 /* 76 * the stats_ API allows a NULL or an empty path to turn off 77 * logging, but the kstat interface has the string buffered, 78 * so we need to make an empty string. 79 */ 80 81 if (path == NULL) 82 path = ""; 83 if ((lc->lc_path[0] == 0) && (path[0] == 0)) 84 goto out; 85 86 (void) strlcpy(lc->lc_path, path, sizeof (lc->lc_path)); 87 88 if (path[0] != '\0') { 89 struct stat64 s; 90 int f; 91 92 exists = access(path, F_OK); 93 /* logfile will be <2GB */ 94 f = open(path, O_WRONLY | O_CREAT, 0666); 95 if (f < 0) { 96 stats_perror(st, error = SE_FILE, 97 gettext("Cannot open/create logfile: %s"), 98 strerror(errno)); 99 goto out; 100 } 101 102 if (fstat64(f, &s) < 0) { 103 stats_perror(st, error = SE_FILE, 104 gettext("Cannot stat logfile: %s"), 105 strerror(errno)); 106 (void) close(f); 107 goto out; 108 } 109 110 /* 111 * the kernel will accept an empty file as a logfile. we must 112 * make sure that we created this empty file, i.e. that it's 113 * not an already existing file that happened to be empty. 114 * 115 * if we hand the kernel a nonempty file, it will check the 116 * magic number. thus, if they hand it something like 117 * /etc/passwd, the kernel should reject it. we just have to 118 * catch the cases of empty files we don't want to be 119 * logfiles. 120 */ 121 122 if ((exists == 0) && (s.st_size == 0LL)) { 123 stats_perror(st, error = SE_INVAL, 124 gettext( 125 "Cannot use existing empty file as a logfile")); 126 (void) close(f); 127 goto out; 128 } 129 130 (void) close(f); 131 } 132 133 if (kstat_write(st->st_kstat_cookie, log, NULL) < 0) { 134 stats_perror(st, error = SE_KERNEL, 135 gettext("Cannot set logfile path for this filesystem")); 136 goto out; 137 } 138 139 out: 140 if ((error != 0) && (path[0] != '\0') && (exists != 0)) 141 (void) unlink(path); 142 143 return (error); 144 } 145 146 int 147 stats_log_which(stats_cookie_t *st, int which, int onoff) 148 { 149 int error = 0; 150 kstat_t *log; 151 cachefs_log_control_t *lc; 152 153 assert(stats_good(st)); 154 155 if ((log = stats_log_kstat_read(st)) == NULL) { 156 error = stats_errno(st); 157 goto out; 158 } 159 160 lc = (cachefs_log_control_t *)log->ks_data; 161 162 if (onoff) 163 CACHEFS_LOG_SET(lc, which); 164 else 165 CACHEFS_LOG_CLEAR(lc, which); 166 167 if (kstat_write(st->st_kstat_cookie, log, NULL) < 0) { 168 stats_perror(st, error = SE_KERNEL, 169 gettext("Cannot set log bitmap for this filesystem")); 170 goto out; 171 } 172 173 out: 174 return (error); 175 } 176 177 char * 178 stats_log_kernel_getname(stats_cookie_t *st) 179 { 180 char *rc = NULL; 181 kstat_t *log; 182 cachefs_log_control_t *lc; 183 184 assert(stats_good(st)); 185 186 if ((log = stats_log_kstat_read(st)) == NULL) 187 goto out; 188 189 lc = (cachefs_log_control_t *)log->ks_data; 190 191 rc = lc->lc_path; /* rc[0] will be '\0' if we're not logging */ 192 193 out: 194 return (rc); 195 } 196 197 static kstat_t * 198 stats_log_kstat_read(stats_cookie_t *st) 199 { 200 kstat_t *rc; 201 202 assert(stats_good(st)); 203 assert(st->st_flags & ST_BOUND); 204 205 if ((rc = kstat_lookup(st->st_kstat_cookie, 206 "cachefs", st->st_fsid, "log")) == NULL) { 207 /* 208 * XXX if st was created for a particular cachedir, we 209 * should scan for another st->st_fsid that'll get us 210 * the same cache. 211 */ 212 stats_perror(st, SE_KERNEL, 213 gettext("Cannot lookup kstats for this filesystem")); 214 goto out; 215 } 216 if (kstat_read(st->st_kstat_cookie, rc, NULL) < 0) { 217 stats_perror(st, SE_KERNEL, 218 gettext("Cannot read kstats for this filesystem")); 219 rc = NULL; 220 goto out; 221 } 222 223 out: 224 return (rc); 225 } 226 227 int 228 stats_log_logfile_open(stats_cookie_t *st, char *fname) 229 { 230 int rc = 0; 231 232 assert(stats_good(st)); 233 234 if ((fname == NULL) || (fname[0] == '\0')) { 235 kstat_t *log; 236 cachefs_log_control_t *lc; 237 238 if ((log = stats_log_kstat_read(st)) == NULL) { 239 rc = -1; 240 goto out; 241 } 242 lc = (cachefs_log_control_t *)log->ks_data; 243 fname = lc->lc_path; 244 } 245 246 /* logfile will be <2GB */ 247 if ((st->st_logstream = fopen(fname, "r")) == NULL) { 248 stats_perror(st, SE_FILE, 249 gettext("Cannot open logfile %s"), fname); 250 rc = -1; 251 goto out; 252 } 253 xdrstdio_create(&st->st_logxdr, st->st_logstream, XDR_DECODE); 254 255 if (! stats_xdr_loghead(&st->st_logxdr, &st->st_loghead)) { 256 stats_perror(st, SE_CORRUPT, 257 gettext("Cannot read header from logfile %s"), fname); 258 rc = -1; 259 goto out; 260 } 261 if (st->st_loghead.lh_magic != CACHEFS_LOG_MAGIC) { 262 stats_perror(st, SE_CORRUPT, 263 gettext("%s: Invalid log file header"), fname); 264 rc = -1; 265 goto out; 266 } 267 if (st->st_loghead.lh_revision > CACHEFS_LOG_FILE_REV) { 268 stats_perror(st, SE_CORRUPT, 269 gettext("%s: Revision too high"), fname); 270 rc = -1; 271 goto out; 272 } 273 274 st->st_flags |= ST_LFOPEN; 275 276 out: 277 if (rc != 0) { 278 if (st->st_logstream != NULL) { 279 (void) fclose(st->st_logstream); 280 st->st_logstream = NULL; 281 } 282 if (st->st_logxdr.x_ops != NULL) { 283 xdr_destroy(&st->st_logxdr); 284 st->st_logxdr.x_ops = NULL; 285 } 286 } 287 return (rc); 288 } 289 290 static bool_t 291 stats_xdr_loghead(XDR *xdrs, struct cachefs_log_logfile_header *lh) 292 { 293 if ((! xdr_u_int(xdrs, &lh->lh_magic)) || 294 (! xdr_u_int(xdrs, &lh->lh_revision)) || 295 (! xdr_int(xdrs, &lh->lh_errno)) || 296 (! xdr_u_int(xdrs, &lh->lh_blocks)) || 297 (! xdr_u_int(xdrs, &lh->lh_files)) || 298 (! xdr_u_int(xdrs, &lh->lh_maxbsize)) || 299 (! xdr_u_int(xdrs, &lh->lh_pagesize))) 300 return (FALSE); 301 302 return (TRUE); 303 } 304 305 void * 306 stats_log_logfile_read(stats_cookie_t *st, int *type) 307 { 308 void *rc = NULL; 309 size_t size; 310 int ttype; 311 XDR *xdrs; 312 char *string1, *string2; 313 314 assert(stats_good(st)); 315 316 xdrs = &st->st_logxdr; 317 318 if (! (st->st_flags & ST_LFOPEN)) { 319 stats_perror(st, SE_INVAL, 320 gettext("Logfile was not open")); 321 goto out; 322 } 323 324 if (type == NULL) 325 type = &ttype; 326 327 if (! xdr_int(xdrs, type)) 328 goto out; 329 330 switch (*type) { 331 struct cachefs_log_mount_record mount, *mountp; 332 struct cachefs_log_umount_record umount; 333 struct cachefs_log_getpage_record getpage; 334 struct cachefs_log_readdir_record readdir; 335 struct cachefs_log_readlink_record readlink; 336 struct cachefs_log_remove_record remove; 337 struct cachefs_log_rmdir_record rmdir; 338 struct cachefs_log_truncate_record truncate; 339 struct cachefs_log_putpage_record putpage; 340 struct cachefs_log_create_record create; 341 struct cachefs_log_mkdir_record mkdir; 342 struct cachefs_log_rename_record rename; 343 struct cachefs_log_symlink_record symlink; 344 struct cachefs_log_populate_record populate; 345 struct cachefs_log_csymlink_record csymlink; 346 struct cachefs_log_filldir_record filldir; 347 struct cachefs_log_mdcreate_record mdcreate; 348 struct cachefs_log_gpfront_record gpfront; 349 struct cachefs_log_rfdir_record rfdir; 350 struct cachefs_log_ualloc_record ualloc; 351 struct cachefs_log_calloc_record challoc; 352 struct cachefs_log_nocache_record nocache; 353 354 case CACHEFS_LOG_MOUNT: 355 if ((! xdr_int(xdrs, &mount.error)) || 356 (! xdr_int(xdrs, (int *)&mount.time)) || 357 (! xdr_opaque(xdrs, (caddr_t)&mount.vfsp, 358 sizeof (mount.vfsp))) || 359 (! xdr_u_int(xdrs, &mount.flags)) || 360 (! xdr_u_int(xdrs, &mount.popsize)) || 361 (! xdr_u_int(xdrs, &mount.fgsize)) || 362 (! xdr_u_short(xdrs, &mount.pathlen)) || 363 (! xdr_u_short(xdrs, &mount.cacheidlen))) { 364 stats_perror(st, SE_CORRUPT, 365 gettext("Truncated mount record")); 366 goto out; 367 } 368 mount.type = *type; 369 size = sizeof (mount) + mount.pathlen + mount.cacheidlen - 370 CLPAD(cachefs_log_mount_record, path); 371 if ((rc = mountp = 372 (struct cachefs_log_mount_record *) 373 calloc(1, size)) == NULL) { 374 stats_perror(st, SE_NOMEM, 375 gettext("Cannot malloc record")); 376 goto out; 377 } 378 memcpy(rc, &mount, size); 379 string1 = mountp->path; 380 string2 = mountp->path + mount.pathlen + 1; 381 (void) xdr_wrapstring(xdrs, &string1); 382 (void) xdr_wrapstring(xdrs, &string2); 383 break; 384 385 case CACHEFS_LOG_UMOUNT: 386 if ((! xdr_int(xdrs, &umount.error)) || 387 (! xdr_int(xdrs, (int *)&umount.time)) || 388 (! xdr_opaque(xdrs, (caddr_t)&umount.vfsp, 389 sizeof (umount.vfsp)))) { 390 stats_perror(st, SE_CORRUPT, 391 gettext("Truncated umount record")); 392 goto out; 393 } 394 umount.type = *type; 395 size = sizeof (umount); 396 if ((rc = (caddr_t)calloc(1, size)) == NULL) { 397 stats_perror(st, SE_NOMEM, 398 gettext("Cannot malloc record")); 399 goto out; 400 } 401 memcpy(rc, &umount, size); 402 break; 403 404 case CACHEFS_LOG_GETPAGE: 405 if ((! xdr_int(xdrs, &getpage.error)) || 406 (! xdr_int(xdrs, (int *)&getpage.time)) || 407 (! xdr_opaque(xdrs, (caddr_t)&getpage.vfsp, 408 sizeof (getpage.vfsp))) || 409 (! xdr_opaque(xdrs, (caddr_t)&getpage.fid, 410 sizeof (getpage.fid))) || 411 (! xdr_u_longlong_t(xdrs, 412 (u_longlong_t *)&getpage.fileno)) || 413 (! xdr_int(xdrs, (int *)&getpage.uid)) || 414 (! xdr_u_longlong_t(xdrs, 415 (u_longlong_t *)&getpage.offset)) || 416 (! xdr_u_int(xdrs, &getpage.len))) { 417 stats_perror(st, SE_CORRUPT, 418 gettext("Truncated getpage record")); 419 goto out; 420 } 421 getpage.type = *type; 422 size = sizeof (getpage); 423 if ((rc = (caddr_t)calloc(1, size)) == NULL) { 424 stats_perror(st, SE_NOMEM, 425 gettext("Cannot malloc record")); 426 goto out; 427 } 428 memcpy(rc, &getpage, size); 429 break; 430 431 case CACHEFS_LOG_READDIR: 432 if ((! xdr_int(xdrs, &readdir.error)) || 433 (! xdr_int(xdrs, (int *)&readdir.time)) || 434 (! xdr_opaque(xdrs, (caddr_t)&readdir.vfsp, 435 sizeof (readdir.vfsp))) || 436 (! xdr_opaque(xdrs, (caddr_t)&readdir.fid, 437 sizeof (readdir.fid))) || 438 (! xdr_u_longlong_t(xdrs, 439 (u_longlong_t *)&readdir.fileno)) || 440 (! xdr_int(xdrs, (int *)&readdir.uid)) || 441 (! xdr_u_longlong_t(xdrs, 442 (u_longlong_t *)&readdir.offset)) || 443 (! xdr_int(xdrs, &readdir.eof))) { 444 stats_perror(st, SE_CORRUPT, 445 gettext("Truncated readdir record")); 446 goto out; 447 } 448 readdir.type = *type; 449 size = sizeof (readdir); 450 if ((rc = (caddr_t)calloc(1, size)) == NULL) { 451 stats_perror(st, SE_NOMEM, 452 gettext("Cannot malloc record")); 453 goto out; 454 } 455 memcpy(rc, &readdir, size); 456 break; 457 458 case CACHEFS_LOG_READLINK: 459 if ((! xdr_int(xdrs, &readlink.error)) || 460 (! xdr_int(xdrs, (int *)&readlink.time)) || 461 (! xdr_opaque(xdrs, (caddr_t)&readlink.vfsp, 462 sizeof (readlink.vfsp))) || 463 (! xdr_opaque(xdrs, (caddr_t)&readlink.fid, 464 sizeof (readlink.fid))) || 465 (! xdr_u_longlong_t(xdrs, 466 (u_longlong_t *)&readlink.fileno)) || 467 (! xdr_int(xdrs, (int *)&readlink.uid)) || 468 (! xdr_u_int(xdrs, 469 &readlink.length))) { 470 stats_perror(st, SE_CORRUPT, 471 gettext("Truncated readlink record")); 472 goto out; 473 } 474 readlink.type = *type; 475 size = sizeof (readlink); 476 if ((rc = (caddr_t)calloc(1, size)) == NULL) { 477 stats_perror(st, SE_NOMEM, 478 gettext("Cannot malloc record")); 479 goto out; 480 } 481 memcpy(rc, &readlink, size); 482 break; 483 484 case CACHEFS_LOG_REMOVE: 485 if ((! xdr_int(xdrs, &remove.error)) || 486 (! xdr_int(xdrs, (int *)&remove.time)) || 487 (! xdr_opaque(xdrs, (caddr_t)&remove.vfsp, 488 sizeof (remove.vfsp))) || 489 (! xdr_opaque(xdrs, (caddr_t)&remove.fid, 490 sizeof (remove.fid))) || 491 (! xdr_u_longlong_t(xdrs, 492 (u_longlong_t *)&remove.fileno)) || 493 (! xdr_int(xdrs, (int *)&remove.uid))) { 494 stats_perror(st, SE_CORRUPT, 495 gettext("Truncated remove record")); 496 goto out; 497 } 498 remove.type = *type; 499 size = sizeof (remove); 500 if ((rc = (caddr_t)calloc(1, size)) == NULL) { 501 stats_perror(st, SE_NOMEM, 502 gettext("Cannot malloc record")); 503 goto out; 504 } 505 memcpy(rc, &remove, size); 506 break; 507 508 case CACHEFS_LOG_RMDIR: 509 if ((! xdr_int(xdrs, &rmdir.error)) || 510 (! xdr_int(xdrs, (int *)&rmdir.time)) || 511 (! xdr_opaque(xdrs, (caddr_t)&rmdir.vfsp, 512 sizeof (rmdir.vfsp))) || 513 (! xdr_opaque(xdrs, (caddr_t)&rmdir.fid, 514 sizeof (rmdir.fid))) || 515 (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&rmdir.fileno)) || 516 (! xdr_int(xdrs, (int *)&rmdir.uid))) { 517 stats_perror(st, SE_CORRUPT, 518 gettext("Truncated rmdir record")); 519 goto out; 520 } 521 rmdir.type = *type; 522 size = sizeof (rmdir); 523 if ((rc = (caddr_t)calloc(1, size)) == NULL) { 524 stats_perror(st, SE_NOMEM, 525 gettext("Cannot malloc record")); 526 goto out; 527 } 528 memcpy(rc, &rmdir, size); 529 break; 530 531 case CACHEFS_LOG_TRUNCATE: 532 if ((! xdr_int(xdrs, &truncate.error)) || 533 (! xdr_int(xdrs, (int *)&truncate.time)) || 534 (! xdr_opaque(xdrs, (caddr_t)&truncate.vfsp, 535 sizeof (truncate.vfsp))) || 536 (! xdr_opaque(xdrs, (caddr_t)&truncate.fid, 537 sizeof (truncate.fid))) || 538 (! xdr_u_longlong_t(xdrs, 539 (u_longlong_t *)&truncate.fileno)) || 540 (! xdr_int(xdrs, (int *)&truncate.uid)) || 541 (! xdr_u_longlong_t(xdrs, 542 (u_longlong_t *)&truncate.size))) { 543 stats_perror(st, SE_CORRUPT, 544 gettext("Truncated truncate record")); 545 goto out; 546 } 547 truncate.type = *type; 548 size = sizeof (truncate); 549 if ((rc = (caddr_t)calloc(1, size)) == NULL) { 550 stats_perror(st, SE_NOMEM, 551 gettext("Cannot malloc record")); 552 goto out; 553 } 554 memcpy(rc, &truncate, size); 555 break; 556 557 case CACHEFS_LOG_PUTPAGE: 558 if ((! xdr_int(xdrs, &putpage.error)) || 559 (! xdr_int(xdrs, (int *)&putpage.time)) || 560 (! xdr_opaque(xdrs, (caddr_t)&putpage.vfsp, 561 sizeof (putpage.vfsp))) || 562 (! xdr_opaque(xdrs, (caddr_t)&putpage.fid, 563 sizeof (putpage.fid))) || 564 (! xdr_u_longlong_t(xdrs, 565 (u_longlong_t *)&putpage.fileno)) || 566 (! xdr_int(xdrs, (int *)&putpage.uid)) || 567 (! xdr_u_longlong_t(xdrs, 568 (u_longlong_t *)&putpage.offset)) || 569 (! xdr_u_int(xdrs, &putpage.len))) { 570 stats_perror(st, SE_CORRUPT, 571 gettext("Truncated putpage record")); 572 goto out; 573 } 574 putpage.type = *type; 575 size = sizeof (putpage); 576 if ((rc = (caddr_t)calloc(1, size)) == NULL) { 577 stats_perror(st, SE_NOMEM, 578 gettext("Cannot malloc record")); 579 goto out; 580 } 581 memcpy(rc, &putpage, size); 582 break; 583 584 case CACHEFS_LOG_CREATE: 585 if ((! xdr_int(xdrs, &create.error)) || 586 (! xdr_int(xdrs, (int *)&create.time)) || 587 (! xdr_opaque(xdrs, (caddr_t)&create.vfsp, 588 sizeof (create.vfsp))) || 589 (! xdr_opaque(xdrs, (caddr_t)&create.fid, 590 sizeof (create.fid))) || 591 (! xdr_u_longlong_t(xdrs, 592 (u_longlong_t *)&create.fileno)) || 593 (! xdr_int(xdrs, (int *)&create.uid))) { 594 stats_perror(st, SE_CORRUPT, 595 gettext("Truncated create record")); 596 goto out; 597 } 598 create.type = *type; 599 size = sizeof (create); 600 if ((rc = (struct cachefs_log_create_record *) 601 calloc(1, size)) == NULL) { 602 stats_perror(st, SE_NOMEM, 603 gettext("Cannot malloc record")); 604 goto out; 605 } 606 memcpy(rc, &create, size); 607 break; 608 609 case CACHEFS_LOG_MKDIR: 610 if ((! xdr_int(xdrs, &mkdir.error)) || 611 (! xdr_int(xdrs, (int *)&mkdir.time)) || 612 (! xdr_opaque(xdrs, (caddr_t)&mkdir.vfsp, 613 sizeof (mkdir.vfsp))) || 614 (! xdr_opaque(xdrs, (caddr_t)&mkdir.fid, 615 sizeof (mkdir.fid))) || 616 (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&mkdir.fileno)) || 617 (! xdr_int(xdrs, (int *)&mkdir.uid))) { 618 stats_perror(st, SE_CORRUPT, 619 gettext("Truncated mkdir record")); 620 goto out; 621 } 622 mkdir.type = *type; 623 size = sizeof (mkdir); 624 if ((rc = (struct cachefs_log_mkdir_record *) 625 calloc(1, size)) == NULL) { 626 stats_perror(st, SE_NOMEM, 627 gettext("Cannot malloc record")); 628 goto out; 629 } 630 memcpy(rc, &mkdir, size); 631 break; 632 633 case CACHEFS_LOG_RENAME: 634 if ((! xdr_int(xdrs, &rename.error)) || 635 (! xdr_int(xdrs, (int *)&rename.time)) || 636 (! xdr_opaque(xdrs, (caddr_t)&rename.vfsp, 637 sizeof (rename.vfsp))) || 638 (! xdr_opaque(xdrs, (caddr_t)&rename.gone, 639 sizeof (rename.gone))) || 640 (! xdr_int(xdrs, &rename.removed)) || 641 (! xdr_int(xdrs, (int *)&rename.uid))) { 642 stats_perror(st, SE_CORRUPT, 643 gettext("Truncated rename record")); 644 goto out; 645 } 646 rename.type = *type; 647 size = sizeof (rename); 648 if ((rc = (struct cachefs_log_rename_record *) 649 calloc(1, size)) == NULL) { 650 stats_perror(st, SE_NOMEM, 651 gettext("Cannot malloc record")); 652 goto out; 653 } 654 memcpy(rc, &rename, size); 655 break; 656 657 case CACHEFS_LOG_SYMLINK: 658 if ((! xdr_int(xdrs, &symlink.error)) || 659 (! xdr_int(xdrs, (int *)&symlink.time)) || 660 (! xdr_opaque(xdrs, (caddr_t)&symlink.vfsp, 661 sizeof (symlink.vfsp))) || 662 (! xdr_opaque(xdrs, (caddr_t)&symlink.fid, 663 sizeof (symlink.fid))) || 664 (! xdr_u_longlong_t(xdrs, 665 (u_longlong_t *)&symlink.fileno)) || 666 (! xdr_int(xdrs, (int *)&symlink.uid)) || 667 (! xdr_u_int(xdrs, &symlink.size))) { 668 stats_perror(st, SE_CORRUPT, 669 gettext("Truncated symlink record")); 670 goto out; 671 } 672 symlink.type = *type; 673 size = sizeof (symlink); 674 if ((rc = (struct cachefs_log_symlink_record *) 675 calloc(1, size)) == NULL) { 676 stats_perror(st, SE_NOMEM, 677 gettext("Cannot malloc record")); 678 goto out; 679 } 680 memcpy(rc, &symlink, size); 681 break; 682 683 case CACHEFS_LOG_POPULATE: 684 if ((! xdr_int(xdrs, &populate.error)) || 685 (! xdr_int(xdrs, (int *)&populate.time)) || 686 (! xdr_opaque(xdrs, (caddr_t)&populate.vfsp, 687 sizeof (populate.vfsp))) || 688 (! xdr_opaque(xdrs, (caddr_t)&populate.fid, 689 sizeof (populate.fid))) || 690 (! xdr_u_longlong_t(xdrs, 691 (u_longlong_t *)&populate.fileno)) || 692 (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&populate.off)) || 693 (! xdr_u_int(xdrs, &populate.size))) { 694 stats_perror(st, SE_CORRUPT, 695 gettext("Truncated populate record")); 696 goto out; 697 } 698 populate.type = *type; 699 if ((rc = (struct cachefs_log_populate_record *) 700 calloc(1, sizeof (populate))) == NULL) { 701 stats_perror(st, SE_NOMEM, 702 gettext("Cannot malloc record")); 703 goto out; 704 } 705 memcpy(rc, &populate, sizeof (populate)); 706 break; 707 708 case CACHEFS_LOG_CSYMLINK: 709 if ((! xdr_int(xdrs, &csymlink.error)) || 710 (! xdr_int(xdrs, (int *)&csymlink.time)) || 711 (! xdr_opaque(xdrs, (caddr_t)&csymlink.vfsp, 712 sizeof (csymlink.vfsp))) || 713 (! xdr_opaque(xdrs, (caddr_t)&csymlink.fid, 714 sizeof (csymlink.fid))) || 715 (! xdr_u_longlong_t(xdrs, 716 (u_longlong_t *)&csymlink.fileno)) || 717 (! xdr_int(xdrs, &csymlink.size))) { 718 stats_perror(st, SE_CORRUPT, 719 gettext("Truncated csymlink record")); 720 goto out; 721 } 722 csymlink.type = *type; 723 if ((rc = (struct cachefs_log_csymlink_record *) 724 calloc(1, sizeof (csymlink))) == NULL) { 725 stats_perror(st, SE_NOMEM, 726 gettext("Cannot malloc record")); 727 goto out; 728 } 729 memcpy(rc, &csymlink, sizeof (csymlink)); 730 break; 731 732 case CACHEFS_LOG_FILLDIR: 733 if ((! xdr_int(xdrs, &filldir.error)) || 734 (! xdr_int(xdrs, (int *)&filldir.time)) || 735 (! xdr_opaque(xdrs, (caddr_t)&filldir.vfsp, 736 sizeof (filldir.vfsp))) || 737 (! xdr_opaque(xdrs, (caddr_t)&filldir.fid, 738 sizeof (filldir.fid))) || 739 (! xdr_u_longlong_t(xdrs, 740 (u_longlong_t *)&filldir.fileno)) || 741 (! xdr_int(xdrs, &filldir.size))) { 742 stats_perror(st, SE_CORRUPT, 743 gettext("Truncated filldir record")); 744 goto out; 745 } 746 filldir.type = *type; 747 if ((rc = (struct cachefs_log_filldir_record *) 748 calloc(1, sizeof (filldir))) == NULL) { 749 stats_perror(st, SE_NOMEM, 750 gettext("Cannot malloc record")); 751 goto out; 752 } 753 memcpy(rc, &filldir, sizeof (filldir)); 754 break; 755 756 case CACHEFS_LOG_MDCREATE: 757 if ((! xdr_int(xdrs, &mdcreate.error)) || 758 (! xdr_int(xdrs, (int *)&mdcreate.time)) || 759 (! xdr_opaque(xdrs, (caddr_t)&mdcreate.vfsp, 760 sizeof (mdcreate.vfsp))) || 761 (! xdr_opaque(xdrs, (caddr_t)&mdcreate.fid, 762 sizeof (mdcreate.fid))) || 763 (! xdr_u_longlong_t(xdrs, 764 (u_longlong_t *)&mdcreate.fileno)) || 765 (! xdr_u_int(xdrs, &mdcreate.count))) { 766 stats_perror(st, SE_CORRUPT, 767 gettext("Truncated mdcreate record")); 768 goto out; 769 } 770 mdcreate.type = *type; 771 if ((rc = (struct cachefs_log_mdcreate_record *) 772 calloc(1, sizeof (mdcreate))) == NULL) { 773 stats_perror(st, SE_NOMEM, 774 gettext("Cannot malloc record")); 775 goto out; 776 } 777 memcpy(rc, &mdcreate, sizeof (mdcreate)); 778 break; 779 780 case CACHEFS_LOG_GPFRONT: 781 if ((! xdr_int(xdrs, &gpfront.error)) || 782 (! xdr_int(xdrs, (int *)&gpfront.time)) || 783 (! xdr_opaque(xdrs, (caddr_t)&gpfront.vfsp, 784 sizeof (gpfront.vfsp))) || 785 (! xdr_opaque(xdrs, (caddr_t)&gpfront.fid, 786 sizeof (gpfront.fid))) || 787 (! xdr_u_longlong_t(xdrs, 788 (u_longlong_t *)&gpfront.fileno)) || 789 (! xdr_int(xdrs, (int *)&gpfront.uid)) || 790 (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&gpfront.off)) || 791 (! xdr_u_int(xdrs, &gpfront.len))) { 792 stats_perror(st, SE_CORRUPT, 793 gettext("Truncated gpfront record")); 794 goto out; 795 } 796 gpfront.type = *type; 797 if ((rc = (struct cachefs_log_gpfront_record *) 798 calloc(1, sizeof (gpfront))) == NULL) { 799 stats_perror(st, SE_NOMEM, 800 gettext("Cannot malloc record")); 801 goto out; 802 } 803 memcpy(rc, &gpfront, sizeof (gpfront)); 804 break; 805 806 case CACHEFS_LOG_RFDIR: 807 if ((! xdr_int(xdrs, &rfdir.error)) || 808 (! xdr_int(xdrs, (int *)&rfdir.time)) || 809 (! xdr_opaque(xdrs, (caddr_t)&rfdir.vfsp, 810 sizeof (rfdir.vfsp))) || 811 (! xdr_opaque(xdrs, (caddr_t)&rfdir.fid, 812 sizeof (rfdir.fid))) || 813 (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&rfdir.fileno)) || 814 (! xdr_int(xdrs, (int *)&rfdir.uid))) { 815 stats_perror(st, SE_CORRUPT, 816 gettext("Truncated rfdir record")); 817 goto out; 818 } 819 rfdir.type = *type; 820 if ((rc = (struct cachefs_log_rfdir_record *) 821 calloc(1, sizeof (rfdir))) == NULL) { 822 stats_perror(st, SE_NOMEM, 823 gettext("Cannot malloc record")); 824 goto out; 825 } 826 memcpy(rc, &rfdir, sizeof (rfdir)); 827 break; 828 829 case CACHEFS_LOG_UALLOC: 830 if ((! xdr_int(xdrs, &ualloc.error)) || 831 (! xdr_int(xdrs, (int *)&ualloc.time)) || 832 (! xdr_opaque(xdrs, (caddr_t)&ualloc.vfsp, 833 sizeof (ualloc.vfsp))) || 834 (! xdr_opaque(xdrs, (caddr_t)&ualloc.fid, 835 sizeof (ualloc.fid))) || 836 (! xdr_u_longlong_t(xdrs, 837 (u_longlong_t *)&ualloc.fileno)) || 838 (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&ualloc.off)) || 839 (! xdr_u_int(xdrs, &ualloc.len))) { 840 stats_perror(st, SE_CORRUPT, 841 gettext("Truncated ualloc record")); 842 goto out; 843 } 844 ualloc.type = *type; 845 if ((rc = (struct cachefs_log_ualloc_record *) 846 calloc(1, sizeof (ualloc))) == NULL) { 847 stats_perror(st, SE_NOMEM, 848 gettext("Cannot malloc record")); 849 goto out; 850 } 851 memcpy(rc, &ualloc, sizeof (ualloc)); 852 break; 853 854 case CACHEFS_LOG_CALLOC: 855 if ((! xdr_int(xdrs, &challoc.error)) || 856 (! xdr_int(xdrs, (int *)&challoc.time)) || 857 (! xdr_opaque(xdrs, (caddr_t)&challoc.vfsp, 858 sizeof (challoc.vfsp))) || 859 (! xdr_opaque(xdrs, (caddr_t)&challoc.fid, 860 sizeof (challoc.fid))) || 861 (! xdr_u_longlong_t(xdrs, 862 (u_longlong_t *)&challoc.fileno)) || 863 (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&challoc.off)) || 864 (! xdr_u_int(xdrs, &challoc.len))) { 865 stats_perror(st, SE_CORRUPT, 866 gettext("Truncated calloc record")); 867 goto out; 868 } 869 challoc.type = *type; 870 if ((rc = (struct cachefs_log_calloc_record *) 871 calloc(1, sizeof (challoc))) == NULL) { 872 stats_perror(st, SE_NOMEM, 873 gettext("Cannot malloc record")); 874 goto out; 875 } 876 memcpy(rc, &challoc, sizeof (challoc)); 877 break; 878 879 case CACHEFS_LOG_NOCACHE: 880 if ((! xdr_int(xdrs, &nocache.error)) || 881 (! xdr_int(xdrs, (int *)&nocache.time)) || 882 (! xdr_opaque(xdrs, (caddr_t)&nocache.vfsp, 883 sizeof (nocache.vfsp))) || 884 (! xdr_opaque(xdrs, (caddr_t)&nocache.fid, 885 sizeof (nocache.fid))) || 886 (! xdr_u_longlong_t(xdrs, 887 (u_longlong_t *)&nocache.fileno))) { 888 stats_perror(st, SE_CORRUPT, 889 gettext("Truncated nocache record")); 890 goto out; 891 } 892 nocache.type = *type; 893 if ((rc = (struct cachefs_log_nocache_record *) 894 calloc(1, sizeof (nocache))) == NULL) { 895 stats_perror(st, SE_NOMEM, 896 gettext("Cannot malloc record")); 897 goto out; 898 } 899 memcpy(rc, &nocache, sizeof (nocache)); 900 break; 901 902 default: 903 stats_perror(st, SE_CORRUPT, 904 gettext("Corrupt logfile (position %x)"), 905 ftell(st->st_logstream)); 906 break; 907 } 908 909 out: 910 return (rc); 911 } 912 913 /* 914 * convert a logfile record (read by stats_log_logfile_read()) to 915 * ascii. probably not for end-user consumption, but this should be 916 * the official way to do it. 917 */ 918 919 char * 920 stats_log_record_toascii(stats_cookie_t *st, void *recp) 921 { 922 int rectype = *((int *)recp); 923 int recerror = *((int *)recp + 1); 924 time_t tt = *((time_t *)((int *)recp + 2)); 925 struct tm *tm = localtime(&tt); 926 char buffy[BUFSIZ], *fidstr, *fidstr2, *fidstr3; 927 928 struct cachefs_log_mount_record *mountp; 929 struct cachefs_log_umount_record *umountp; 930 struct cachefs_log_getpage_record *getpagep; 931 struct cachefs_log_readdir_record *readdirp; 932 struct cachefs_log_readlink_record *readlinkp; 933 struct cachefs_log_remove_record *removep; 934 struct cachefs_log_rmdir_record *rmdirp; 935 struct cachefs_log_truncate_record *truncatep; 936 struct cachefs_log_putpage_record *putpagep; 937 struct cachefs_log_create_record *createp; 938 struct cachefs_log_mkdir_record *mkdirp; 939 struct cachefs_log_rename_record *renamep; 940 struct cachefs_log_symlink_record *symlinkp; 941 struct cachefs_log_populate_record *populatep; 942 struct cachefs_log_csymlink_record *csymlinkp; 943 struct cachefs_log_filldir_record *filldirp; 944 struct cachefs_log_mdcreate_record *mdcreatep; 945 struct cachefs_log_gpfront_record *gpfrontp; 946 struct cachefs_log_rfdir_record *rfdirp; 947 struct cachefs_log_ualloc_record *uallocp; 948 struct cachefs_log_calloc_record *callocp; 949 struct cachefs_log_nocache_record *nocachep; 950 951 assert(stats_good(st)); 952 953 (void) sprintf(st->st_asciirec, "%2d/%-2d %2d:%.2d %2d", 954 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, 955 recerror); 956 957 switch (rectype) { 958 case CACHEFS_LOG_MOUNT: 959 mountp = (struct cachefs_log_mount_record *)recp; 960 (void) snprintf(buffy, sizeof (buffy), 961 " %-8s %llx %8x %d %d %s (%s)", "Mount", mountp->vfsp, 962 mountp->flags, mountp->popsize, 963 mountp->fgsize, mountp->path, 964 mountp->path + mountp->pathlen + 1); 965 (void) strlcat(st->st_asciirec, buffy, 966 sizeof (st->st_asciirec)); 967 break; 968 969 case CACHEFS_LOG_UMOUNT: 970 umountp = (struct cachefs_log_umount_record *)recp; 971 (void) snprintf(buffy, sizeof (buffy), " %-8s %llx", 972 "Umount", umountp->vfsp); 973 (void) strlcat(st->st_asciirec, buffy, 974 sizeof (st->st_asciirec)); 975 break; 976 977 case CACHEFS_LOG_GETPAGE: 978 getpagep = (struct cachefs_log_getpage_record *)recp; 979 (void) snprintf(buffy, sizeof (buffy), 980 " %-8s %llx %s %llu %ld %llu %u", 981 "Getpage", 982 getpagep->vfsp, fidstr = stats_log_fmtfid(&getpagep->fid), 983 getpagep->fileno, 984 getpagep->uid, getpagep->offset, getpagep->len); 985 (void) strlcat(st->st_asciirec, buffy, 986 sizeof (st->st_asciirec)); 987 free(fidstr); 988 break; 989 990 case CACHEFS_LOG_READDIR: 991 readdirp = (struct cachefs_log_readdir_record *)recp; 992 (void) snprintf(buffy, sizeof (buffy), 993 " %-8s %llx %s %llu %d %llx %d", "Readdir", 994 readdirp->vfsp, fidstr = stats_log_fmtfid(&readdirp->fid), 995 readdirp->fileno, 996 readdirp->uid, readdirp->offset, readdirp->eof); 997 (void) strlcat(st->st_asciirec, buffy, 998 sizeof (st->st_asciirec)); 999 free(fidstr); 1000 break; 1001 1002 case CACHEFS_LOG_READLINK: 1003 readlinkp = (struct cachefs_log_readlink_record *)recp; 1004 (void) snprintf(buffy, sizeof (buffy), 1005 " %-8s %llx %s %llu %d %u", "Readlink", 1006 readlinkp->vfsp, 1007 fidstr = stats_log_fmtfid(&readlinkp->fid), 1008 readlinkp->fileno, 1009 readlinkp->uid, readlinkp->length); 1010 (void) strlcat(st->st_asciirec, buffy, 1011 sizeof (st->st_asciirec)); 1012 free(fidstr); 1013 break; 1014 1015 case CACHEFS_LOG_REMOVE: 1016 removep = (struct cachefs_log_remove_record *)recp; 1017 (void) snprintf(buffy, sizeof (buffy), 1018 " %-8s %llx %s %llu %d", "Remove", 1019 removep->vfsp, fidstr = stats_log_fmtfid(&removep->fid), 1020 removep->fileno, 1021 removep->uid); 1022 (void) strlcat(st->st_asciirec, buffy, 1023 sizeof (st->st_asciirec)); 1024 free(fidstr); 1025 break; 1026 1027 case CACHEFS_LOG_RMDIR: 1028 rmdirp = (struct cachefs_log_rmdir_record *)recp; 1029 (void) snprintf(buffy, sizeof (buffy), 1030 " %-8s %llx %s %llu %d", "Rmdir", 1031 rmdirp->vfsp, fidstr = stats_log_fmtfid(&rmdirp->fid), 1032 rmdirp->fileno, 1033 rmdirp->uid); 1034 (void) strlcat(st->st_asciirec, buffy, 1035 sizeof (st->st_asciirec)); 1036 free(fidstr); 1037 break; 1038 1039 case CACHEFS_LOG_TRUNCATE: 1040 truncatep = (struct cachefs_log_truncate_record *)recp; 1041 (void) snprintf(buffy, sizeof (buffy), 1042 " %-8s %llx %s %llu %d %llu", "Truncate", 1043 truncatep->vfsp, 1044 fidstr = stats_log_fmtfid(&truncatep->fid), 1045 truncatep->fileno, 1046 truncatep->uid, truncatep->size); 1047 (void) strlcat(st->st_asciirec, buffy, 1048 sizeof (st->st_asciirec)); 1049 free(fidstr); 1050 break; 1051 1052 case CACHEFS_LOG_PUTPAGE: 1053 putpagep = (struct cachefs_log_putpage_record *)recp; 1054 (void) snprintf(buffy, sizeof (buffy), 1055 " %-8s %llx %s %llu %d %llu %u", "Putpage", 1056 putpagep->vfsp, fidstr = stats_log_fmtfid(&putpagep->fid), 1057 putpagep->fileno, 1058 putpagep->uid, putpagep->offset, putpagep->len); 1059 (void) strlcat(st->st_asciirec, buffy, 1060 sizeof (st->st_asciirec)); 1061 free(fidstr); 1062 break; 1063 1064 case CACHEFS_LOG_CREATE: 1065 createp = (struct cachefs_log_create_record *)recp; 1066 (void) snprintf(buffy, sizeof (buffy), 1067 " %-8s %llx %s %llu %d", "Create", 1068 createp->vfsp, 1069 fidstr = stats_log_fmtfid(&createp->fid), 1070 createp->fileno, 1071 createp->uid); 1072 (void) strlcat(st->st_asciirec, buffy, 1073 sizeof (st->st_asciirec)); 1074 free(fidstr); 1075 break; 1076 1077 case CACHEFS_LOG_MKDIR: 1078 mkdirp = (struct cachefs_log_mkdir_record *)recp; 1079 (void) snprintf(buffy, sizeof (buffy), 1080 " %-8s %llx %s %llu %d", "Mkdir", 1081 mkdirp->vfsp, 1082 fidstr = stats_log_fmtfid(&mkdirp->fid), 1083 mkdirp->fileno, 1084 mkdirp->uid); 1085 (void) strlcat(st->st_asciirec, buffy, 1086 sizeof (st->st_asciirec)); 1087 free(fidstr); 1088 break; 1089 1090 case CACHEFS_LOG_RENAME: 1091 renamep = (struct cachefs_log_rename_record *)recp; 1092 (void) snprintf(buffy, sizeof (buffy), 1093 " %-8s %llx %s %llu %d %d", "Rename", 1094 renamep->vfsp, 1095 fidstr = stats_log_fmtfid(&renamep->gone), 1096 renamep->fileno, 1097 renamep->removed, renamep->uid); 1098 (void) strlcat(st->st_asciirec, buffy, 1099 sizeof (st->st_asciirec)); 1100 free(fidstr); 1101 break; 1102 1103 case CACHEFS_LOG_SYMLINK: 1104 symlinkp = (struct cachefs_log_symlink_record *)recp; 1105 (void) snprintf(buffy, sizeof (buffy), 1106 " %-8s %llx %s %llu %d %u", "Symlink", 1107 symlinkp->vfsp, 1108 fidstr = stats_log_fmtfid(&symlinkp->fid), 1109 symlinkp->fileno, 1110 symlinkp->uid, symlinkp->size); 1111 (void) strlcat(st->st_asciirec, buffy, 1112 sizeof (st->st_asciirec)); 1113 free(fidstr); 1114 break; 1115 1116 case CACHEFS_LOG_POPULATE: 1117 populatep = (struct cachefs_log_populate_record *)recp; 1118 (void) snprintf(buffy, sizeof (buffy), 1119 " %-8s %llx %s %llu %llu %d", "Populate", 1120 populatep->vfsp, 1121 fidstr = stats_log_fmtfid(&populatep->fid), 1122 populatep->fileno, 1123 populatep->off, populatep->size); 1124 (void) strlcat(st->st_asciirec, buffy, 1125 sizeof (st->st_asciirec)); 1126 free(fidstr); 1127 break; 1128 1129 case CACHEFS_LOG_CSYMLINK: 1130 csymlinkp = (struct cachefs_log_csymlink_record *)recp; 1131 (void) snprintf(buffy, sizeof (buffy), 1132 " %-8s %llx %s %llu %d", "Csymlink", 1133 csymlinkp->vfsp, 1134 fidstr = stats_log_fmtfid(&csymlinkp->fid), 1135 csymlinkp->fileno, 1136 csymlinkp->size); 1137 (void) strlcat(st->st_asciirec, buffy, 1138 sizeof (st->st_asciirec)); 1139 free(fidstr); 1140 break; 1141 1142 case CACHEFS_LOG_FILLDIR: 1143 filldirp = (struct cachefs_log_filldir_record *)recp; 1144 (void) snprintf(buffy, sizeof (buffy), 1145 " %-8s %llx %s %llu %d", "Filldir", 1146 filldirp->vfsp, 1147 fidstr = stats_log_fmtfid(&filldirp->fid), 1148 filldirp->fileno, 1149 filldirp->size); 1150 (void) strlcat(st->st_asciirec, buffy, 1151 sizeof (st->st_asciirec)); 1152 free(fidstr); 1153 break; 1154 1155 case CACHEFS_LOG_MDCREATE: 1156 mdcreatep = (struct cachefs_log_mdcreate_record *)recp; 1157 (void) snprintf(buffy, sizeof (buffy), 1158 " %-8s %llx %s %llu %u", "Mdcreate", 1159 mdcreatep->vfsp, 1160 fidstr = stats_log_fmtfid(&mdcreatep->fid), 1161 mdcreatep->fileno, mdcreatep->count); 1162 (void) strlcat(st->st_asciirec, buffy, 1163 sizeof (st->st_asciirec)); 1164 free(fidstr); 1165 break; 1166 1167 case CACHEFS_LOG_GPFRONT: 1168 gpfrontp = (struct cachefs_log_gpfront_record *)recp; 1169 (void) snprintf(buffy, sizeof (buffy), 1170 " %-8s %llx %s %llu %d %llu %u", "Gpfront", 1171 gpfrontp->vfsp, 1172 fidstr = stats_log_fmtfid(&gpfrontp->fid), 1173 gpfrontp->fileno, 1174 gpfrontp->uid, gpfrontp->off, gpfrontp->len); 1175 (void) strlcat(st->st_asciirec, buffy, 1176 sizeof (st->st_asciirec)); 1177 free(fidstr); 1178 break; 1179 1180 case CACHEFS_LOG_RFDIR: 1181 rfdirp = (struct cachefs_log_rfdir_record *)recp; 1182 (void) snprintf(buffy, sizeof (buffy), 1183 " %-8s %llx %s %llu %d", "Rfdir", 1184 rfdirp->vfsp, 1185 fidstr = stats_log_fmtfid(&rfdirp->fid), 1186 rfdirp->fileno, 1187 rfdirp->uid); 1188 (void) strlcat(st->st_asciirec, buffy, 1189 sizeof (st->st_asciirec)); 1190 free(fidstr); 1191 break; 1192 1193 case CACHEFS_LOG_UALLOC: 1194 uallocp = (struct cachefs_log_ualloc_record *)recp; 1195 (void) snprintf(buffy, sizeof (buffy), 1196 " %-8s %llx %s %llu %llu %u", "Ualloc", 1197 uallocp->vfsp, 1198 fidstr = stats_log_fmtfid(&uallocp->fid), 1199 uallocp->fileno, 1200 uallocp->off, uallocp->len); 1201 (void) strlcat(st->st_asciirec, buffy, 1202 sizeof (st->st_asciirec)); 1203 free(fidstr); 1204 break; 1205 1206 case CACHEFS_LOG_CALLOC: 1207 callocp = (struct cachefs_log_calloc_record *)recp; 1208 (void) snprintf(buffy, sizeof (buffy), 1209 " %-8s %llx %s %llu %llu %u", "Calloc", 1210 callocp->vfsp, 1211 fidstr = stats_log_fmtfid(&callocp->fid), 1212 callocp->fileno, callocp->off, callocp->len); 1213 (void) strlcat(st->st_asciirec, buffy, 1214 sizeof (st->st_asciirec)); 1215 free(fidstr); 1216 break; 1217 1218 case CACHEFS_LOG_NOCACHE: 1219 nocachep = (struct cachefs_log_nocache_record *)recp; 1220 (void) snprintf(buffy, sizeof (buffy), 1221 " %-8s %llx %s %llu", "Nocache", 1222 nocachep->vfsp, 1223 fidstr = stats_log_fmtfid(&nocachep->fid), 1224 nocachep->fileno); 1225 (void) strlcat(st->st_asciirec, buffy, 1226 sizeof (st->st_asciirec)); 1227 free(fidstr); 1228 break; 1229 1230 default: 1231 stats_perror(st, SE_CORRUPT, 1232 gettext( 1233 "Attempt to format invalid log type=%d (position %x)"), 1234 rectype, ftell(st->st_logstream)); 1235 return (NULL); 1236 } 1237 1238 return (st->st_asciirec); 1239 } 1240 1241 uint_t 1242 stats_log_get_record_info(stats_cookie_t *sc, 1243 void *recp, caddr_t *vfsp, cfs_fid_t **fidp, ino64_t *filenop, 1244 u_offset_t *offp, u_offset_t *lenp) 1245 { 1246 int type = ((int *)recp)[0]; 1247 int error = ((int *)recp)[1]; 1248 uint_t rc = 0; 1249 1250 struct cachefs_log_getpage_record *getpagep; 1251 struct cachefs_log_readdir_record *readdirp; 1252 struct cachefs_log_readlink_record *readlinkp; 1253 struct cachefs_log_remove_record *removep; 1254 struct cachefs_log_rmdir_record *rmdirp; 1255 struct cachefs_log_truncate_record *truncatep; 1256 struct cachefs_log_putpage_record *putpagep; 1257 struct cachefs_log_create_record *createp; 1258 struct cachefs_log_mkdir_record *mkdirp; 1259 struct cachefs_log_rename_record *renamep; 1260 struct cachefs_log_symlink_record *symlinkp; 1261 struct cachefs_log_populate_record *populatep; 1262 struct cachefs_log_csymlink_record *csymlinkp; 1263 struct cachefs_log_filldir_record *filldirp; 1264 struct cachefs_log_mdcreate_record *mdcreatep; 1265 struct cachefs_log_gpfront_record *gpfrontp; 1266 struct cachefs_log_rfdir_record *rfdirp; 1267 struct cachefs_log_ualloc_record *uallocp; 1268 struct cachefs_log_calloc_record *callocp; 1269 struct cachefs_log_nocache_record *nocachep; 1270 1271 switch (type) { 1272 case CACHEFS_LOG_RFDIR: 1273 if ((error == EINVAL) || (error == ENOENT)) 1274 error = 0; 1275 break; 1276 } 1277 1278 if (error != 0) 1279 return (0); 1280 1281 switch (type) { 1282 case CACHEFS_LOG_GETPAGE: 1283 getpagep = (struct cachefs_log_getpage_record *)recp; 1284 *fidp = &getpagep->fid; 1285 *filenop = getpagep->fileno; 1286 *vfsp = (caddr_t)(uintptr_t)getpagep->vfsp; 1287 *offp = getpagep->offset; 1288 *lenp = (u_offset_t)getpagep->len; 1289 rc = (GRI_ADD | GRI_EXPENSIVE); 1290 break; 1291 1292 case CACHEFS_LOG_READDIR: 1293 readdirp = (struct cachefs_log_readdir_record *)recp; 1294 *fidp = &readdirp->fid; 1295 *filenop = readdirp->fileno; 1296 *vfsp = (caddr_t)(uintptr_t)readdirp->vfsp; 1297 *offp = readdirp->offset; 1298 *lenp = (u_offset_t)sc->st_loghead.lh_maxbsize; 1299 rc = (GRI_ADD | GRI_EXPENSIVE); 1300 break; 1301 1302 case CACHEFS_LOG_READLINK: 1303 readlinkp = (struct cachefs_log_readlink_record *)recp; 1304 *fidp = &readlinkp->fid; 1305 *filenop = readlinkp->fileno; 1306 *vfsp = (caddr_t)(uintptr_t)readlinkp->vfsp; 1307 *offp = 0LL; 1308 *lenp = (u_offset_t)((readlinkp->length > C_FSL_SIZE) ? 1309 readlinkp->length : 0); 1310 rc = (GRI_ADD | GRI_EXPENSIVE); 1311 break; 1312 1313 case CACHEFS_LOG_REMOVE: 1314 removep = (struct cachefs_log_remove_record *)recp; 1315 *fidp = &removep->fid; 1316 *filenop = removep->fileno; 1317 *vfsp = (caddr_t)(uintptr_t)removep->vfsp; 1318 *offp = *lenp = 0LL; 1319 rc = (GRI_TRUNC | GRI_MODIFY); 1320 break; 1321 1322 case CACHEFS_LOG_RMDIR: 1323 rmdirp = (struct cachefs_log_rmdir_record *)recp; 1324 *fidp = &rmdirp->fid; 1325 *filenop = rmdirp->fileno; 1326 *vfsp = (caddr_t)(uintptr_t)rmdirp->vfsp; 1327 *offp = *lenp = 0LL; 1328 rc = (GRI_TRUNC | GRI_MODIFY); 1329 break; 1330 1331 case CACHEFS_LOG_TRUNCATE: 1332 truncatep = (struct cachefs_log_truncate_record *)recp; 1333 *fidp = &truncatep->fid; 1334 *filenop = truncatep->fileno; 1335 *vfsp = (caddr_t)(uintptr_t)truncatep->vfsp; 1336 *offp = 0LL; 1337 *lenp = truncatep->size; 1338 rc = (GRI_TRUNC | GRI_MODIFY); 1339 break; 1340 1341 case CACHEFS_LOG_PUTPAGE: 1342 putpagep = (struct cachefs_log_putpage_record *)recp; 1343 *fidp = &putpagep->fid; 1344 *filenop = putpagep->fileno; 1345 *vfsp = (caddr_t)(uintptr_t)putpagep->vfsp; 1346 *offp = putpagep->offset; 1347 *lenp = (u_offset_t)putpagep->len; 1348 rc = (GRI_ADD | GRI_MODIFY); 1349 break; 1350 1351 case CACHEFS_LOG_CREATE: 1352 createp = (struct cachefs_log_create_record *)recp; 1353 *fidp = &createp->fid; 1354 *filenop = createp->fileno; 1355 *vfsp = (caddr_t)(uintptr_t)createp->vfsp; 1356 *offp = *lenp = 0LL; 1357 rc = (GRI_ADD | GRI_MODIFY); 1358 break; 1359 1360 case CACHEFS_LOG_MKDIR: 1361 mkdirp = (struct cachefs_log_mkdir_record *)recp; 1362 *fidp = &mkdirp->fid; 1363 *filenop = mkdirp->fileno; 1364 *vfsp = (caddr_t)(uintptr_t)mkdirp->vfsp; 1365 *offp = *lenp = 0LL; 1366 rc = (GRI_ADD | GRI_MODIFY); 1367 break; 1368 1369 case CACHEFS_LOG_RENAME: 1370 renamep = (struct cachefs_log_rename_record *)recp; 1371 *fidp = &renamep->gone; 1372 *filenop = renamep->fileno; 1373 *vfsp = (caddr_t)(uintptr_t)renamep->vfsp; 1374 *offp = *lenp = 0LL; 1375 rc = GRI_MODIFY; 1376 if (renamep->removed) 1377 rc |= GRI_TRUNC; 1378 break; 1379 1380 case CACHEFS_LOG_SYMLINK: 1381 symlinkp = (struct cachefs_log_symlink_record *)recp; 1382 *fidp = &symlinkp->fid; 1383 *filenop = symlinkp->fileno; 1384 *vfsp = (caddr_t)(uintptr_t)symlinkp->vfsp; 1385 *offp = 0LL; 1386 *lenp = (u_offset_t)((symlinkp->size > C_FSL_SIZE) ? 1387 symlinkp->size : 0); 1388 rc = (GRI_ADD | GRI_MODIFY); 1389 break; 1390 1391 case CACHEFS_LOG_POPULATE: 1392 populatep = (struct cachefs_log_populate_record *)recp; 1393 *fidp = &populatep->fid; 1394 *filenop = populatep->fileno; 1395 *vfsp = (caddr_t)(uintptr_t)populatep->vfsp; 1396 *offp = populatep->off; 1397 *lenp = (u_offset_t)populatep->size; 1398 rc = GRI_ADD; 1399 break; 1400 1401 case CACHEFS_LOG_CSYMLINK: 1402 csymlinkp = (struct cachefs_log_csymlink_record *)recp; 1403 *fidp = &csymlinkp->fid; 1404 *filenop = csymlinkp->fileno; 1405 *vfsp = (caddr_t)(uintptr_t)csymlinkp->vfsp; 1406 *offp = 0LL; 1407 *lenp = (u_offset_t)((csymlinkp->size > C_FSL_SIZE) ? 1408 csymlinkp->size : 0); 1409 rc = GRI_ADD; 1410 break; 1411 1412 case CACHEFS_LOG_FILLDIR: 1413 filldirp = (struct cachefs_log_filldir_record *)recp; 1414 *fidp = &filldirp->fid; 1415 *filenop = filldirp->fileno; 1416 *vfsp = (caddr_t)(uintptr_t)filldirp->vfsp; 1417 *offp = 0LL; 1418 *lenp = (u_offset_t)(filldirp->size); 1419 rc = GRI_ADD; 1420 break; 1421 1422 case CACHEFS_LOG_MDCREATE: 1423 mdcreatep = (struct cachefs_log_mdcreate_record *)recp; 1424 *fidp = &mdcreatep->fid; 1425 *filenop = mdcreatep->fileno; 1426 *vfsp = (caddr_t)(uintptr_t)mdcreatep->vfsp; 1427 *lenp = (u_offset_t)mdcreatep->count; 1428 rc = GRI_METADATA; 1429 break; 1430 1431 case CACHEFS_LOG_GPFRONT: 1432 gpfrontp = (struct cachefs_log_gpfront_record *)recp; 1433 *fidp = &gpfrontp->fid; 1434 *filenop = gpfrontp->fileno; 1435 *vfsp = (caddr_t)(uintptr_t)gpfrontp->vfsp; 1436 *offp = gpfrontp->off; 1437 *lenp = (u_offset_t)sc->st_loghead.lh_pagesize; 1438 rc = (GRI_ADD | GRI_EXPENSIVE); 1439 break; 1440 1441 case CACHEFS_LOG_RFDIR: 1442 rfdirp = (struct cachefs_log_rfdir_record *)recp; 1443 rfdirp->error = 0; 1444 *fidp = &rfdirp->fid; 1445 *filenop = rfdirp->fileno; 1446 *vfsp = (caddr_t)(uintptr_t)rfdirp->vfsp; 1447 *offp = 0LL; 1448 *lenp = (u_offset_t)sc->st_loghead.lh_maxbsize; 1449 rc = (GRI_ADD | GRI_EXPENSIVE); 1450 break; 1451 1452 case CACHEFS_LOG_UALLOC: 1453 uallocp = (struct cachefs_log_ualloc_record *)recp; 1454 *fidp = &uallocp->fid; 1455 *filenop = uallocp->fileno; 1456 *vfsp = (caddr_t)(uintptr_t)uallocp->vfsp; 1457 *offp = uallocp->off; 1458 *lenp = (u_offset_t)uallocp->len; 1459 rc = (GRI_ADD); 1460 break; 1461 1462 case CACHEFS_LOG_CALLOC: 1463 callocp = (struct cachefs_log_calloc_record *)recp; 1464 *fidp = &callocp->fid; 1465 *filenop = callocp->fileno; 1466 *vfsp = (caddr_t)(uintptr_t)callocp->vfsp; 1467 *offp = callocp->off; 1468 *lenp = (u_offset_t)callocp->len; 1469 rc = (GRI_ADD | GRI_EXPENSIVE); 1470 break; 1471 1472 case CACHEFS_LOG_NOCACHE: 1473 nocachep = (struct cachefs_log_nocache_record *)recp; 1474 *fidp = &nocachep->fid; 1475 *filenop = nocachep->fileno; 1476 *vfsp = (caddr_t)(uintptr_t)nocachep->vfsp; 1477 *offp = *lenp = 0LL; 1478 rc = (GRI_TRUNC); 1479 break; 1480 } 1481 1482 return (rc); 1483 } 1484 1485 /* 1486 * ascii formatter for fids. returns a malloc()ed string -- it's up to 1487 * the caller to free it. 1488 */ 1489 1490 static char * 1491 stats_log_fmtfid(cfs_fid_t *fidp) 1492 { 1493 char buffy[BUFSIZ], *rc; 1494 1495 (void) strcpy(buffy, "<fid>"); 1496 1497 rc = strdup(buffy); 1498 if (rc == NULL) 1499 rc = "out of memory"; 1500 1501 return (rc); 1502 } 1503 1504 void 1505 stats_log_fi_add(stats_cookie_t *st, fid_info *fip, u_offset_t off, 1506 u_offset_t len) 1507 { 1508 int i, j; 1509 u_offset_t iend, jend, tmp; 1510 1511 assert(stats_good(st)); 1512 assert(st->st_flags & ST_DBMOPEN); 1513 assert(st->st_flags & ST_LFOPEN); 1514 1515 /* shortcut if we had some sort of zero-length thing */ 1516 1517 if (len == 0LL) 1518 return; 1519 1520 /* `smear' the offset and length to block boundaries */ 1521 1522 /* 1523 * pre-largefiles: iend = off & ~(st->st_loghead.lh_maxbsize - 1); 1524 * largefiles: make sure that we ~ all bits in the 64 bit 1525 * version of (st->st_loghead.lh_maxbsize - 1) 1526 */ 1527 tmp = (u_offset_t)(st->st_loghead.lh_maxbsize - 1); 1528 iend = off & ~tmp; 1529 1530 jend = off + len; 1531 jend += (u_offset_t)(st->st_loghead.lh_maxbsize - 1); 1532 /* 1533 * pre-largefiles: jend &= ~(st->st_loghead.lh_maxbsize - 1); 1534 * largefiles: make sure that we ~ all bits in the 64 bit 1535 * version of (st->st_loghead.lh_maxbsize - 1) 1536 */ 1537 jend &= ~tmp; 1538 1539 off = iend; 1540 len = jend - off; 1541 1542 /* see if our offset falls within an existing chunk */ 1543 for (i = 0; i < fip->fi_ent_n; i++) { 1544 iend = fip->fi_ent[i].offset + fip->fi_ent[i].len; 1545 if ((fip->fi_ent[i].offset <= off) && (iend >= off)) 1546 break; 1547 } 1548 1549 /* update the chunk, or make a new one */ 1550 if (i < fip->fi_ent_n) { 1551 if ((off + len) > iend) 1552 fip->fi_ent[i].len = off + len - fip->fi_ent[i].offset; 1553 } else if (i < C_MAX_ALLOCINFO_SLOTS) { 1554 fip->fi_ent_n = i + 1; 1555 fip->fi_ent[i].offset = off; 1556 fip->fi_ent[i].len = len; 1557 } else { 1558 /* cachefs does a nocache, so we'll immitate */ 1559 1560 /* 1561 * XXX we're free to grow again. assume we got 1562 * inactivated right away -- the worst case! 1563 */ 1564 1565 fip->fi_ent_n = 0; 1566 fip->fi_total = 0LL; 1567 } 1568 1569 /* quit for the trivial (hopefully the usual) case... */ 1570 if (fip->fi_ent_n <= 1) { 1571 if (fip->fi_ent_n == 0) 1572 fip->fi_total = 0LL; 1573 else 1574 fip->fi_total = fip->fi_ent[0].len; 1575 return; 1576 } 1577 1578 /* 1579 * we have to see if we can consolidate any chunks. the 1580 * chunks aren't guaranteed to be in any kind of order, so we 1581 * do a qsort. otherwise, the consolidation would be N^2 (but 1582 * we're probably close here). 1583 */ 1584 1585 qsort(fip->fi_ent, fip->fi_ent_n, sizeof (fip->fi_ent[0]), 1586 stats_log_fi_comp); 1587 1588 /* tag non-essential entries with offset == -1, and consolidate */ 1589 for (i = 0; i < fip->fi_ent_n - 1; i++) { 1590 if ((offset_t)fip->fi_ent[i].offset < 0) 1591 continue; 1592 iend = fip->fi_ent[i].offset + fip->fi_ent[i].len; 1593 1594 for (j = i + 1; j < fip->fi_ent_n; j++) { 1595 if (iend < fip->fi_ent[j].offset) 1596 break; 1597 jend = fip->fi_ent[j].offset + fip->fi_ent[j].len; 1598 if (jend >= iend) 1599 fip->fi_ent[i].len = 1600 jend - fip->fi_ent[i].offset; 1601 fip->fi_ent[j].offset = (u_offset_t)-1; 1602 } 1603 } 1604 1605 /* get rid of non-essential entries (without preserving order) */ 1606 for (i = 0; i < fip->fi_ent_n; i++) 1607 if ((offset_t)fip->fi_ent[i].offset < 0) 1608 fip->fi_ent[i--] = fip->fi_ent[--(fip->fi_ent_n)]; 1609 1610 /* add up the new total size */ 1611 for (i = fip->fi_total = 0LL; i < fip->fi_ent_n; i++) 1612 fip->fi_total += fip->fi_ent[i].len; 1613 } 1614 1615 static int 1616 stats_log_fi_comp(const void *a, const void *b) 1617 { 1618 struct fid_info_allocent *fa = (struct fid_info_allocent *)a; 1619 struct fid_info_allocent *fb = (struct fid_info_allocent *)b; 1620 1621 if ((offset_t)(fa->offset - fb->offset) > 0) 1622 return (1); 1623 if ((offset_t)(fa->offset - fb->offset) < 0) 1624 return (-1); 1625 return (0); 1626 } 1627 1628 void 1629 stats_log_fi_trunc(stats_cookie_t *st, fid_info *fip, u_offset_t off, 1630 u_offset_t len) 1631 { 1632 fip->fi_ent_n = 1; 1633 fip->fi_ent[0].offset = off; 1634 fip->fi_ent[0].len = len; 1635 fip->fi_total = len; 1636 } 1637 1638 struct cachefs_log_logfile_header * 1639 stats_log_getheader(stats_cookie_t *st) 1640 { 1641 assert(stats_good(st)); 1642 assert(st->st_flags & ST_LFOPEN); 1643 1644 return (&st->st_loghead); 1645 } 1646 1647 void 1648 stats_log_compute_wssize(stats_cookie_t *st) 1649 { 1650 void *record; 1651 int type; 1652 struct cachefs_log_mount_record *mountp; 1653 struct cachefs_log_umount_record *umountp; 1654 datum key; 1655 caddr_t vfsp; 1656 mount_info *mi = NULL, *mip; 1657 size_t len1, len2, maxlen; 1658 char *string1, *string2; 1659 uint_t rflags; 1660 fid_info fi, *fip; 1661 cfs_fid_t *fidp; 1662 ino64_t fileno; 1663 u_offset_t off; 1664 u_offset_t len; 1665 struct cachefs_log_logfile_header *lh = &st->st_loghead; 1666 size_t delta; 1667 1668 assert(stats_good(st)); 1669 assert(st->st_flags & ST_LFOPEN); 1670 assert(st->st_flags & ST_DBMOPEN); 1671 1672 /* 1673 * The maximum size of a mount_info structure is the size of 1674 * the structure less the space already defined for char mi_path[] 1675 * plus the maximum size of mi_path. 1676 * 1677 * Additional space is allocated to mi_path at runtime using 1678 * malloc(). The size needs to be calculated in-situ as ANSI C 1679 * will only allow 'sizeof expression' or 'sizeof (type)'. 1680 */ 1681 1682 mi = malloc(sizeof (*mi) - sizeof (mi->mi_path) + MI_MAX_MI_PATH); 1683 if (mi == NULL) { 1684 stats_perror(st, SE_NOMEM, gettext("Out of memory")); 1685 goto out; 1686 } 1687 1688 st->st_ws_init = st->st_loghead.lh_blocks; 1689 1690 while (record = stats_log_logfile_read(st, &type)) { 1691 switch (type) { 1692 case CACHEFS_LOG_MOUNT: 1693 mountp = (struct cachefs_log_mount_record *)record; 1694 if (mountp->error != 0) 1695 break; 1696 for (key = stats_dbm_firstkey(st); 1697 key.dptr != NULL; 1698 key = stats_dbm_nextkey(st)) { 1699 if (key.dsize != sizeof (vfsp)) 1700 continue; 1701 1702 memcpy((caddr_t)&vfsp, key.dptr, 1703 sizeof (vfsp)); 1704 mip = stats_dbm_fetch_byvfsp(st, vfsp); 1705 if (mip == NULL) 1706 continue; 1707 1708 len1 = strlen(mip->mi_path); 1709 len2 = strlen(mip->mi_path + len1 + 1); 1710 memcpy((caddr_t)mi, mip, sizeof (*mi) + 1711 len1 + len2 - CLPAD(mount_info, mi_path)); 1712 free(mip); 1713 1714 string1 = mi->mi_path + len1 + 1; 1715 string2 = mountp->path + mountp->pathlen + 1; 1716 if (strcmp(string1, string2) == 0) { 1717 stats_dbm_delete_byvfsp(st, vfsp); 1718 break; 1719 } 1720 } 1721 if (key.dptr == NULL) { 1722 /* non-idempotent setup stuff */ 1723 memset(mi, '\0', sizeof (*mi)); 1724 mi->mi_flags = mountp->flags; 1725 mi->mi_filegrp_size = mountp->fgsize; 1726 } 1727 1728 /* 1729 * idempotent setup stuff 1730 * 1731 * Careful string handling around mi_path 1732 * is required as it contains two NULL 1733 * terminated strings. 1734 */ 1735 1736 mi->mi_mounted = 1; 1737 maxlen = MI_MAX_MI_PATH - 1; 1738 len1 = strlcpy(mi->mi_path, mountp->path, maxlen); 1739 if (len1 >= maxlen) { 1740 stats_perror(st, SE_CORRUPT, 1741 gettext("Path too long in log file")); 1742 break; 1743 } 1744 1745 len1 = strlen(mi->mi_path); 1746 maxlen = MI_MAX_MI_PATH - (len1 + 1); 1747 len2 = strlcpy(mi->mi_path + len1 + 1, 1748 mountp->path + mountp->pathlen + 1, maxlen); 1749 if (len2 >= maxlen) { 1750 stats_perror(st, SE_CORRUPT, 1751 gettext("CacheID too long in log file")); 1752 break; 1753 } 1754 1755 stats_dbm_store_byvfsp(st, 1756 (caddr_t)(uintptr_t)mountp->vfsp, mi); 1757 break; 1758 1759 case CACHEFS_LOG_UMOUNT: 1760 umountp = (struct cachefs_log_umount_record *)record; 1761 if (umountp->error != 0) 1762 break; 1763 mip = stats_dbm_fetch_byvfsp(st, 1764 (caddr_t)(uintptr_t)umountp->vfsp); 1765 if (mip == NULL) 1766 break; 1767 mip->mi_mounted = 0; 1768 stats_dbm_store_byvfsp(st, 1769 (caddr_t)(uintptr_t)umountp->vfsp, mip); 1770 free(mip); 1771 break; 1772 1773 default: 1774 rflags = stats_log_get_record_info(st, record, 1775 &vfsp, &fidp, &fileno, &off, &len); 1776 if (rflags == 0) /* shortcut */ 1777 break; 1778 1779 mip = stats_dbm_fetch_byvfsp(st, vfsp); 1780 if (mip == NULL) /* hopefully very rare */ 1781 break; 1782 1783 fip = stats_dbm_fetch_byfid(st, fidp); 1784 if (fip == NULL) { 1785 fip = &fi; 1786 memset(&fi, '\0', sizeof (fi)); 1787 fi.fi_vfsp = vfsp; 1788 } 1789 1790 /* account for the creation of the fscache */ 1791 if (! mip->mi_used) { 1792 mip->mi_used = 1; 1793 1794 /* account for the .cfs_option file */ 1795 mip->mi_current += (u_offset_t)lh->lh_maxbsize; 1796 st->st_ws_current += 1797 (u_offset_t)lh->lh_maxbsize; 1798 } 1799 1800 /* 1801 * Add in the size-growth of the attrcache. 1802 * len will be non-zero only for the record type 1803 * CACHEFS_LOG_MDCREATE, and len can't be > 2GB because 1804 * it refers to the number of entries in 1805 * the attribute cache file. 1806 */ 1807 assert(len <= UINT_MAX); 1808 delta = stats_dbm_attrcache_addsize(st, mip, fileno, 1809 (type == CACHEFS_LOG_MDCREATE) ? (uint_t)len : 0); 1810 st->st_ws_current += (u_offset_t)delta; 1811 mip->mi_current += (u_offset_t)delta; 1812 1813 /* see if this is an `expensive' logfile */ 1814 if ((! st->st_ws_expensive) && (rflags & GRI_EXPENSIVE)) 1815 st->st_ws_expensive = 1; 1816 1817 /* subtract current frontfile size ... */ 1818 st->st_ws_current -= fip->fi_total; 1819 mip->mi_current -= fip->fi_total; 1820 1821 /* compute new frontfile size */ 1822 if ((mip->mi_flags & CFS_WRITE_AROUND) && 1823 (rflags & GRI_MODIFY)) { 1824 fip->fi_total = 0LL; 1825 fip->fi_ent_n = 0; 1826 } else if (rflags & GRI_ADD) { 1827 stats_log_fi_add(st, fip, off, len); 1828 } else if (rflags & GRI_TRUNC) { 1829 stats_log_fi_trunc(st, fip, off, len); 1830 } 1831 if (rflags & GRI_METADATA) 1832 fip->fi_flags |= FI_METADATA; 1833 1834 /* add back in new frontfile size */ 1835 mip->mi_current += fip->fi_total; 1836 if (mip->mi_current > mip->mi_high) 1837 mip->mi_high = mip->mi_current; 1838 stats_dbm_store_byvfsp(st, vfsp, mip); 1839 free(mip); 1840 st->st_ws_current += fip->fi_total; 1841 if (st->st_ws_current > st->st_ws_high) 1842 st->st_ws_high = st->st_ws_current; 1843 1844 stats_dbm_store_byfid(st, fidp, fip); 1845 if (fip != &fi) 1846 free(fip); 1847 break; 1848 } 1849 1850 free(record); 1851 1852 if (stats_inerror(st)) 1853 break; 1854 } 1855 1856 out: 1857 if (mi != NULL) 1858 free(mi); 1859 if (! stats_inerror(st)) 1860 st->st_flags |= ST_WSCOMP; 1861 } 1862 1863 int 1864 stats_log_wssize_init(stats_cookie_t *st) 1865 { 1866 assert(stats_good(st)); 1867 assert(st->st_flags & ST_WSCOMP); 1868 1869 return (st->st_ws_init); 1870 } 1871 1872 u_offset_t 1873 stats_log_wssize_current(stats_cookie_t *st) 1874 { 1875 assert(stats_good(st)); 1876 assert(st->st_flags & ST_WSCOMP); 1877 1878 return (st->st_ws_current); 1879 } 1880 1881 u_offset_t 1882 stats_log_wssize_high(stats_cookie_t *st) 1883 { 1884 assert(stats_good(st)); 1885 assert(st->st_flags & ST_WSCOMP); 1886 1887 return (st->st_ws_high); 1888 } 1889 1890 1891 int 1892 stats_log_wssize_expensive(stats_cookie_t *st) 1893 { 1894 assert(stats_good(st)); 1895 assert(st->st_flags & ST_WSCOMP); 1896 1897 return (st->st_ws_expensive); 1898 }