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
stats_log_kernel_setname(stats_cookie_t * st,char * path)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
stats_log_which(stats_cookie_t * st,int which,int onoff)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 *
stats_log_kernel_getname(stats_cookie_t * st)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 *
stats_log_kstat_read(stats_cookie_t * st)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
stats_log_logfile_open(stats_cookie_t * st,char * fname)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
stats_xdr_loghead(XDR * xdrs,struct cachefs_log_logfile_header * lh)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 *
stats_log_logfile_read(stats_cookie_t * st,int * type)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 *
stats_log_record_toascii(stats_cookie_t * st,void * recp)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
stats_log_get_record_info(stats_cookie_t * sc,void * recp,caddr_t * vfsp,cfs_fid_t ** fidp,ino64_t * filenop,u_offset_t * offp,u_offset_t * lenp)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 *
stats_log_fmtfid(cfs_fid_t * fidp)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
stats_log_fi_add(stats_cookie_t * st,fid_info * fip,u_offset_t off,u_offset_t len)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
stats_log_fi_comp(const void * a,const void * b)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
stats_log_fi_trunc(stats_cookie_t * st,fid_info * fip,u_offset_t off,u_offset_t len)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 *
stats_log_getheader(stats_cookie_t * st)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
stats_log_compute_wssize(stats_cookie_t * st)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
stats_log_wssize_init(stats_cookie_t * st)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
stats_log_wssize_current(stats_cookie_t * st)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
stats_log_wssize_high(stats_cookie_t * st)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
stats_log_wssize_expensive(stats_cookie_t * st)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 }
1899