155860Sbostic /*-
261433Sbostic * Copyright (c) 1992, 1993
361433Sbostic * The Regents of the University of California. All rights reserved.
455860Sbostic *
555860Sbostic * %sccs.include.redist.c%
655860Sbostic */
755860Sbostic
855860Sbostic #ifndef lint
961433Sbostic static char copyright[] =
1061433Sbostic "@(#) Copyright (c) 1992, 1993\n\
1161433Sbostic The Regents of the University of California. All rights reserved.\n";
1255860Sbostic #endif /* not lint */
1355860Sbostic
1455860Sbostic #ifndef lint
15*69814Smargo static char sccsid[] = "@(#)cleanerd.c 8.5 (Berkeley) 06/10/95";
1655860Sbostic #endif /* not lint */
1755860Sbostic
1855857Sbostic #include <sys/param.h>
1955857Sbostic #include <sys/mount.h>
2055857Sbostic #include <sys/time.h>
2160096Sbostic
2255857Sbostic #include <ufs/ufs/dinode.h>
2355857Sbostic #include <ufs/lfs/lfs.h>
2460096Sbostic
2560096Sbostic #include <signal.h>
2655857Sbostic #include <stdio.h>
2755857Sbostic #include <stdlib.h>
2855857Sbostic #include <unistd.h>
2955857Sbostic
3055857Sbostic #include "clean.h"
3155857Sbostic char *special = "cleanerd";
3257200Smargo int do_small = 0;
3357200Smargo int do_mmap = 0;
3469668Smargo int stat_report = 0;
3557200Smargo struct cleaner_stats {
3669668Smargo double util_tot;
3769668Smargo double util_sos;
3857200Smargo int blocks_read;
3957200Smargo int blocks_written;
4057200Smargo int segs_cleaned;
4157200Smargo int segs_empty;
4257200Smargo int segs_error;
4357200Smargo } cleaner_stats;
4455857Sbostic
4555857Sbostic struct seglist {
4655857Sbostic int sl_id; /* segment number */
4755857Sbostic int sl_cost; /* cleaning cost */
4869668Smargo char sl_bytes; /* bytes in segment */
4955857Sbostic };
5055857Sbostic
5155857Sbostic struct tossstruct {
5255857Sbostic struct lfs *lfs;
5355857Sbostic int seg;
5455857Sbostic };
5555857Sbostic
5669668Smargo #define CLEAN_BYTES 0x1
5769668Smargo
5855857Sbostic /* function prototypes for system calls; not sure where they should go */
5965737Sbostic int lfs_segwait __P((fsid_t *, struct timeval *));
6065737Sbostic int lfs_segclean __P((fsid_t *, u_long));
6165737Sbostic int lfs_bmapv __P((fsid_t *, BLOCK_INFO *, int));
6265737Sbostic int lfs_markv __P((fsid_t *, BLOCK_INFO *, int));
6355857Sbostic
6455857Sbostic /* function prototypes */
6555857Sbostic int bi_tossold __P((const void *, const void *, const void *));
6655857Sbostic int choose_segments __P((FS_INFO *, struct seglist *,
6755857Sbostic int (*)(FS_INFO *, SEGUSE *)));
6869668Smargo void clean_fs __P((FS_INFO *, int (*)(FS_INFO *, SEGUSE *), int, long));
6969668Smargo int clean_loop __P((FS_INFO *, int, long));
7055857Sbostic int clean_segment __P((FS_INFO *, int));
7155857Sbostic int cost_benefit __P((FS_INFO *, SEGUSE *));
7255857Sbostic int cost_compare __P((const void *, const void *));
7357200Smargo void sig_report __P((int));
7455857Sbostic
7555857Sbostic /*
7655857Sbostic * Cleaning Cost Functions:
7755857Sbostic *
7855857Sbostic * These return the cost of cleaning a segment. The higher the cost value
7955857Sbostic * the better it is to clean the segment, so empty segments have the highest
8055857Sbostic * cost. (It is probably better to think of this as a priority value
8155857Sbostic * instead).
8255857Sbostic *
8355857Sbostic * This is the cost-benefit policy simulated and described in Rosenblum's
8455857Sbostic * 1991 SOSP paper.
8555857Sbostic */
8655857Sbostic
8755857Sbostic int
cost_benefit(fsp,su)8855857Sbostic cost_benefit(fsp, su)
8955857Sbostic FS_INFO *fsp; /* file system information */
9055857Sbostic SEGUSE *su;
9155857Sbostic {
9255857Sbostic struct lfs *lfsp;
9355857Sbostic struct timeval t;
9455857Sbostic int age;
9555857Sbostic int live;
9655857Sbostic
9755857Sbostic gettimeofday(&t, NULL);
9855857Sbostic
9955857Sbostic live = su->su_nbytes;
10060096Sbostic age = t.tv_sec < su->su_lastmod ? 0 : t.tv_sec - su->su_lastmod;
10155857Sbostic
10255857Sbostic lfsp = &fsp->fi_lfs;
10365737Sbostic if (live == 0)
10455857Sbostic return (t.tv_sec * lblkno(lfsp, seg_size(lfsp)));
10555857Sbostic else {
10655857Sbostic /*
10755857Sbostic * from lfsSegUsage.c (Mendel's code).
10855857Sbostic * priority calculation is done using INTEGER arithmetic.
10955857Sbostic * sizes are in BLOCKS (that is why we use lblkno below).
11055857Sbostic * age is in seconds.
11155857Sbostic *
11265737Sbostic * priority = ((seg_size - live) * age) / (seg_size + live)
11355857Sbostic */
11455857Sbostic #ifdef VERBOSE
11555857Sbostic if (live < 0 || live > seg_size(lfsp)) {
11655857Sbostic err(0, "Bad segusage count: %d", live);
11755857Sbostic live = 0;
11855857Sbostic }
11955857Sbostic #endif
12055857Sbostic return (lblkno(lfsp, seg_size(lfsp) - live) * age)
12155857Sbostic / lblkno(lfsp, seg_size(lfsp) + live);
12255857Sbostic }
12355857Sbostic }
12455857Sbostic
12555860Sbostic int
main(argc,argv)12655857Sbostic main(argc, argv)
12755857Sbostic int argc;
12855857Sbostic char *argv[];
12955857Sbostic {
13061371Scgd FS_INFO *fsp;
13155857Sbostic struct statfs *lstatfsp; /* file system stats */
13255857Sbostic struct timeval timeout; /* sleep timeout */
13355857Sbostic fsid_t fsid;
13469668Smargo long clean_opts; /* cleaning options */
13569668Smargo int i, nodaemon, segs_per_clean;
13657200Smargo int opt, cmd_err;
13761371Scgd char *fs_name; /* name of filesystem to clean */
13861371Scgd extern int optind;
13957200Smargo
14061417Scgd cmd_err = nodaemon = 0;
14169668Smargo clean_opts = 0;
14269668Smargo segs_per_clean = 1;
14369668Smargo while ((opt = getopt(argc, argv, "bdmn:r:s")) != EOF) {
14457200Smargo switch (opt) {
14569668Smargo case 'b': /*
14669668Smargo * Use live bytes to determine
14769668Smargo * how many segs to clean.
14869668Smargo */
14969668Smargo clean_opts |= CLEAN_BYTES;
15057200Smargo break;
15169668Smargo case 'd': /* Debug mode. */
15269668Smargo nodaemon = 1;
15369668Smargo break;
15469668Smargo case 'm': /* Use mmap instead of read/write */
15557200Smargo do_mmap = 1;
15657200Smargo break;
15769668Smargo case 'n': /* How many segs to clean at once */
15869668Smargo segs_per_clean = atoi(optarg);
15961417Scgd break;
16069668Smargo case 'r': /* Report every stat_report segments */
16169668Smargo stat_report = atoi(optarg);
16269668Smargo break;
16369668Smargo case 's': /* small writes */
16469668Smargo do_small = 1;
16569668Smargo break;
16657200Smargo default:
16757200Smargo ++cmd_err;
16857200Smargo }
16957200Smargo }
17061371Scgd argc -= optind;
17161371Scgd argv += optind;
17261371Scgd if (cmd_err || (argc != 1))
17361417Scgd err(1, "usage: lfs_cleanerd [-smd] fs_name");
17457200Smargo
17561371Scgd fs_name = argv[0];
17661371Scgd
17765737Sbostic signal(SIGINT, sig_report);
17865737Sbostic signal(SIGUSR1, sig_report);
17965737Sbostic signal(SIGUSR2, sig_report);
18069256Smckusick if (fs_getmntinfo(&lstatfsp, fs_name, "lfs") == 0) {
18161371Scgd /* didn't find the filesystem */
18261371Scgd err(1, "lfs_cleanerd: filesystem %s isn't an LFS!", fs_name);
18361371Scgd }
18455857Sbostic
18561417Scgd if (!nodaemon) /* should we become a daemon, chdir to / & close fd's */
18661417Scgd if (daemon(0, 0) == -1)
18761417Scgd err(1, "lfs_cleanerd: couldn't become a daemon!");
18861417Scgd
18955857Sbostic timeout.tv_sec = 5*60; /* five minutes */
19055857Sbostic timeout.tv_usec = 0;
19155857Sbostic fsid.val[0] = 0;
19255857Sbostic fsid.val[1] = 0;
19355857Sbostic
19461371Scgd for (fsp = get_fs_info(lstatfsp, do_mmap); ;
19561371Scgd reread_fs_info(fsp, do_mmap)) {
19656030Sbostic /*
19761371Scgd * clean the filesystem, and, if it needed cleaning
19861371Scgd * (i.e. it returned nonzero) try it again
19956030Sbostic * to make sure that some nasty process hasn't just
20056030Sbostic * filled the disk system up.
20156030Sbostic */
20269668Smargo if (clean_loop(fsp, segs_per_clean, clean_opts))
20356030Sbostic continue;
20455857Sbostic
20555857Sbostic #ifdef VERBOSE
20655857Sbostic (void)printf("Cleaner going to sleep.\n");
20755857Sbostic #endif
20865737Sbostic if (lfs_segwait(&fsid, &timeout) < 0)
20955857Sbostic err(0, "lfs_segwait: returned error\n");
21055857Sbostic #ifdef VERBOSE
21155857Sbostic (void)printf("Cleaner waking up.\n");
21255857Sbostic #endif
21355857Sbostic }
21455857Sbostic }
21555857Sbostic
21655857Sbostic /* return the number of segments cleaned */
21755857Sbostic int
clean_loop(fsp,nsegs,options)21869668Smargo clean_loop(fsp, nsegs, options)
21955857Sbostic FS_INFO *fsp; /* file system information */
22069668Smargo int nsegs;
22169668Smargo long options;
22255857Sbostic {
22355857Sbostic double loadavg[MAXLOADS];
22455857Sbostic time_t now;
22555857Sbostic u_long max_free_segs;
226*69814Smargo u_long db_per_seg;
22755857Sbostic
22855857Sbostic /*
22955857Sbostic * Compute the maximum possible number of free segments, given the
23055857Sbostic * number of free blocks.
23155857Sbostic */
232*69814Smargo db_per_seg = fsbtodb(&fsp->fi_lfs, fsp->fi_lfs.lfs_ssize);
233*69814Smargo max_free_segs = fsp->fi_lfs.lfs_bfree / db_per_seg;
23455857Sbostic
23555857Sbostic /*
23655857Sbostic * We will clean if there are not enough free blocks or total clean
23755857Sbostic * space is less than BUSY_LIM % of possible clean space.
23855857Sbostic */
23955857Sbostic now = time((time_t *)NULL);
240*69814Smargo #ifdef VERBOSE
241*69814Smargo printf("db_er_seg = %d max_free_segs = %d, bfree = %d avail = %d ",
242*69814Smargo db_per_seg, max_free_segs, fsp->fi_lfs.lfs_bfree,
243*69814Smargo fsp->fi_lfs.lfs_avail);
244*69814Smargo printf("clean = %d\n", fsp->fi_cip->clean);
245*69814Smargo #endif
246*69814Smargo if ((fsp->fi_lfs.lfs_bfree - fsp->fi_lfs.lfs_avail > db_per_seg &&
247*69814Smargo fsp->fi_lfs.lfs_avail < db_per_seg) ||
248*69814Smargo (fsp->fi_cip->clean < max_free_segs &&
24956181Smargo (fsp->fi_cip->clean <= MIN_SEGS(&fsp->fi_lfs) ||
250*69814Smargo fsp->fi_cip->clean < max_free_segs * BUSY_LIM))) {
25156656Sbostic printf("Cleaner Running at %s (%d of %d segments available)\n",
25256656Sbostic ctime(&now), fsp->fi_cip->clean, max_free_segs);
25369668Smargo clean_fs(fsp, cost_benefit, nsegs, options);
25455857Sbostic return (1);
25555857Sbostic } else {
25655857Sbostic /*
25755857Sbostic * We will also clean if the system is reasonably idle and
25855857Sbostic * the total clean space is less then IDLE_LIM % of possible
25955857Sbostic * clean space.
26055857Sbostic */
26155857Sbostic if (getloadavg(loadavg, MAXLOADS) == -1) {
26255857Sbostic perror("getloadavg: failed\n");
26355857Sbostic return (-1);
26455857Sbostic }
26555857Sbostic if (loadavg[ONE_MIN] == 0.0 && loadavg[FIVE_MIN] &&
26655857Sbostic fsp->fi_cip->clean < max_free_segs * IDLE_LIM) {
26769668Smargo clean_fs(fsp, cost_benefit, nsegs, options);
26855857Sbostic printf("Cleaner Running at %s (system idle)\n",
26955857Sbostic ctime(&now));
27055857Sbostic return (1);
27155857Sbostic }
27255857Sbostic }
27355857Sbostic printf("Cleaner Not Running at %s\n", ctime(&now));
27455857Sbostic return (0);
27555857Sbostic }
27655857Sbostic
27755857Sbostic
27855857Sbostic void
clean_fs(fsp,cost_func,nsegs,options)27969668Smargo clean_fs(fsp, cost_func, nsegs, options)
28055857Sbostic FS_INFO *fsp; /* file system information */
28155857Sbostic int (*cost_func) __P((FS_INFO *, SEGUSE *));
28269668Smargo int nsegs;
28369668Smargo long options;
28455857Sbostic {
28555857Sbostic struct seglist *segs, *sp;
28669668Smargo int to_clean, cleaned_bytes;
28755857Sbostic int i;
28855857Sbostic
28965737Sbostic if ((segs =
29065737Sbostic malloc(fsp->fi_lfs.lfs_nseg * sizeof(struct seglist))) == NULL) {
29155857Sbostic err(0, "malloc failed");
29255857Sbostic return;
29355857Sbostic }
29455857Sbostic i = choose_segments(fsp, segs, cost_func);
29555857Sbostic #ifdef VERBOSE
29656051Sbostic printf("clean_fs: found %d segments to clean in file system %s\n",
29755857Sbostic i, fsp->fi_statfsp->f_mntonname);
29855857Sbostic fflush(stdout);
29955857Sbostic #endif
30069668Smargo if (i) {
30169668Smargo /* Check which cleaning algorithm to use. */
30269668Smargo if (options & CLEAN_BYTES) {
30369668Smargo cleaned_bytes = 0;
30469668Smargo to_clean = nsegs <<
30569668Smargo (fsp->fi_lfs.lfs_segshift + fsp->fi_lfs.lfs_bshift);
30669668Smargo for (sp = segs; i && cleaned_bytes < to_clean;
30769668Smargo i--, ++sp) {
30869668Smargo if (clean_segment(fsp, sp->sl_id) < 0)
30969668Smargo perror("clean_segment failed");
31069668Smargo else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,
31169668Smargo sp->sl_id) < 0)
31269668Smargo perror("lfs_segclean failed");
31369668Smargo printf("Cleaned segment %d (%d bytes)\n",
31469668Smargo sp->sl_id, sp->sl_bytes);
31569668Smargo cleaned_bytes += sp->sl_bytes;
31669668Smargo }
31769668Smargo } else
31869668Smargo for (i = MIN(i, nsegs), sp = segs; i-- ; ++sp) {
31969668Smargo if (clean_segment(fsp, sp->sl_id) < 0)
32069668Smargo perror("clean_segment failed");
32169668Smargo else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,
32269668Smargo sp->sl_id) < 0)
32369668Smargo perror("lfs_segclean failed");
32469668Smargo printf("Completed cleaning segment %d\n", sp->sl_id);
32569668Smargo }
32669668Smargo }
32755857Sbostic free(segs);
32855857Sbostic }
32955857Sbostic
33055857Sbostic /*
33155857Sbostic * Segment with the highest priority get sorted to the beginning of the
33255857Sbostic * list. This sort assumes that empty segments always have a higher
33355857Sbostic * cost/benefit than any utilized segment.
33455857Sbostic */
33555857Sbostic int
cost_compare(a,b)33655857Sbostic cost_compare(a, b)
33755857Sbostic const void *a;
33855857Sbostic const void *b;
33955857Sbostic {
34055857Sbostic return (((struct seglist *)b)->sl_cost -
34155857Sbostic ((struct seglist *)a)->sl_cost);
34255857Sbostic }
34355857Sbostic
34455857Sbostic
34555857Sbostic /*
34655857Sbostic * Returns the number of segments to be cleaned with the elements of seglist
34755857Sbostic * filled in.
34855857Sbostic */
34955857Sbostic int
choose_segments(fsp,seglist,cost_func)35055857Sbostic choose_segments(fsp, seglist, cost_func)
35155857Sbostic FS_INFO *fsp;
35255857Sbostic struct seglist *seglist;
35355857Sbostic int (*cost_func) __P((FS_INFO *, SEGUSE *));
35455857Sbostic {
35555857Sbostic struct lfs *lfsp;
35655857Sbostic struct seglist *sp;
35755857Sbostic SEGUSE *sup;
35855857Sbostic int i, nsegs;
35955857Sbostic
36055857Sbostic lfsp = &fsp->fi_lfs;
36155857Sbostic
36255857Sbostic #ifdef VERBOSE
36365737Sbostic (void)printf("Entering choose_segments\n");
36455857Sbostic #endif
36555857Sbostic dump_super(lfsp);
36655857Sbostic dump_cleaner_info(fsp->fi_cip);
36755857Sbostic
36855857Sbostic for (sp = seglist, i = 0; i < lfsp->lfs_nseg; ++i) {
36955857Sbostic sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, i);
37055857Sbostic PRINT_SEGUSE(sup, i);
37155857Sbostic if (!(sup->su_flags & SEGUSE_DIRTY) ||
37255857Sbostic sup->su_flags & SEGUSE_ACTIVE)
37355857Sbostic continue;
37455857Sbostic #ifdef VERBOSE
37565737Sbostic (void)printf("\tchoosing segment %d\n", i);
37655857Sbostic #endif
37755857Sbostic sp->sl_cost = (*cost_func)(fsp, sup);
37855857Sbostic sp->sl_id = i;
37969668Smargo sp->sl_bytes = sup->su_nbytes;
38055857Sbostic ++sp;
38155857Sbostic }
38255857Sbostic nsegs = sp - seglist;
38355857Sbostic qsort(seglist, nsegs, sizeof(struct seglist), cost_compare);
38455857Sbostic #ifdef VERBOSE
38555857Sbostic (void)printf("Returning %d segments\n", nsegs);
38655857Sbostic #endif
38755857Sbostic return (nsegs);
38855857Sbostic }
38955857Sbostic
39055857Sbostic
39155857Sbostic int
clean_segment(fsp,id)39255857Sbostic clean_segment(fsp, id)
39355857Sbostic FS_INFO *fsp; /* file system information */
39455857Sbostic int id; /* segment number */
39555857Sbostic {
39657200Smargo BLOCK_INFO *block_array, *bp;
39755857Sbostic SEGUSE *sp;
39855857Sbostic struct lfs *lfsp;
39955857Sbostic struct tossstruct t;
40055857Sbostic caddr_t seg_buf;
40169668Smargo double util;
40257200Smargo int num_blocks, maxblocks, clean_blocks;
40355857Sbostic
40455857Sbostic lfsp = &fsp->fi_lfs;
40555857Sbostic sp = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, id);
40655857Sbostic
40755857Sbostic #ifdef VERBOSE
40865737Sbostic (void)printf("cleaning segment %d: contains %lu bytes\n", id,
40955857Sbostic sp->su_nbytes);
41055857Sbostic fflush(stdout);
41155857Sbostic #endif
41255857Sbostic /* XXX could add debugging to verify that segment is really empty */
41357200Smargo if (sp->su_nbytes == sp->su_nsums * LFS_SUMMARY_SIZE) {
41457200Smargo ++cleaner_stats.segs_empty;
41555857Sbostic return (0);
41657200Smargo }
41755857Sbostic
41855857Sbostic /* map the segment into a buffer */
41957200Smargo if (mmap_segment(fsp, id, &seg_buf, do_mmap) < 0) {
42055857Sbostic err(0, "mmap_segment failed");
42157200Smargo ++cleaner_stats.segs_error;
42255857Sbostic return (-1);
42355857Sbostic }
42455857Sbostic /* get a list of blocks that are contained by the segment */
42555931Sbostic if (lfs_segmapv(fsp, id, seg_buf, &block_array, &num_blocks) < 0) {
42655857Sbostic err(0, "clean_segment: lfs_segmapv failed");
42757200Smargo ++cleaner_stats.segs_error;
42855857Sbostic return (-1);
42955857Sbostic }
43057200Smargo cleaner_stats.blocks_read += fsp->fi_lfs.lfs_ssize;
43155857Sbostic
43255857Sbostic #ifdef VERBOSE
43365737Sbostic (void)printf("lfs_segmapv returned %d blocks\n", num_blocks);
43465737Sbostic fflush(stdout);
43555857Sbostic #endif
43655857Sbostic
43755857Sbostic /* get the current disk address of blocks contained by the segment */
43865737Sbostic if (lfs_bmapv(&fsp->fi_statfsp->f_fsid, block_array, num_blocks) < 0) {
43955857Sbostic perror("clean_segment: lfs_bmapv failed\n");
44057200Smargo ++cleaner_stats.segs_error;
44155857Sbostic return -1;
44255857Sbostic }
44355857Sbostic
44455857Sbostic /* Now toss any blocks not in the current segment */
44555857Sbostic t.lfs = lfsp;
44655857Sbostic t.seg = id;
44755857Sbostic toss(block_array, &num_blocks, sizeof(BLOCK_INFO), bi_tossold, &t);
44855857Sbostic
44955857Sbostic /* Check if last element should be tossed */
45055857Sbostic if (num_blocks && bi_tossold(&t, block_array + num_blocks - 1, NULL))
45155857Sbostic --num_blocks;
45255857Sbostic
45355857Sbostic #ifdef VERBOSE
45455857Sbostic {
45555857Sbostic BLOCK_INFO *_bip;
45655857Sbostic u_long *lp;
45755857Sbostic int i;
45855857Sbostic
45965737Sbostic (void)printf("after bmapv still have %d blocks\n", num_blocks);
46065737Sbostic fflush(stdout);
46155857Sbostic if (num_blocks)
46255857Sbostic printf("BLOCK INFOS\n");
46355857Sbostic for (_bip = block_array, i=0; i < num_blocks; ++_bip, ++i) {
46455857Sbostic PRINT_BINFO(_bip);
46555857Sbostic lp = (u_long *)_bip->bi_bp;
46655857Sbostic }
46755857Sbostic }
46869668Smargo
46955857Sbostic #endif
47069668Smargo ++cleaner_stats.segs_cleaned;
47157200Smargo cleaner_stats.blocks_written += num_blocks;
47269668Smargo util = ((double)num_blocks / fsp->fi_lfs.lfs_ssize);
47369668Smargo cleaner_stats.util_tot += util;
47469668Smargo cleaner_stats.util_sos += util * util;
47569668Smargo
47657200Smargo if (do_small)
47757200Smargo maxblocks = MAXPHYS / fsp->fi_lfs.lfs_bsize - 1;
47857200Smargo else
47957200Smargo maxblocks = num_blocks;
48057200Smargo
48157200Smargo for (bp = block_array; num_blocks > 0; bp += clean_blocks) {
48257200Smargo clean_blocks = maxblocks < num_blocks ? maxblocks : num_blocks;
48365737Sbostic if (lfs_markv(&fsp->fi_statfsp->f_fsid,
48465737Sbostic bp, clean_blocks) < 0) {
48556051Sbostic err(0, "clean_segment: lfs_markv failed");
48657200Smargo ++cleaner_stats.segs_error;
48755857Sbostic return (-1);
48855857Sbostic }
48957200Smargo num_blocks -= clean_blocks;
49057200Smargo }
49157200Smargo
49255857Sbostic free(block_array);
49365737Sbostic munmap_segment(fsp, seg_buf, do_mmap);
49469668Smargo if (stat_report && cleaner_stats.segs_cleaned % stat_report == 0)
49569668Smargo sig_report(SIGUSR1);
49655857Sbostic return (0);
49755857Sbostic }
49855857Sbostic
49955857Sbostic
50055857Sbostic int
bi_tossold(client,a,b)50155857Sbostic bi_tossold(client, a, b)
50255857Sbostic const void *client;
50355857Sbostic const void *a;
50455857Sbostic const void *b;
50555857Sbostic {
50655857Sbostic const struct tossstruct *t;
50755857Sbostic
50855857Sbostic t = (struct tossstruct *)client;
50955857Sbostic
51055857Sbostic return (((BLOCK_INFO *)a)->bi_daddr == LFS_UNUSED_DADDR ||
51155857Sbostic datosn(t->lfs, ((BLOCK_INFO *)a)->bi_daddr) != t->seg);
51255857Sbostic }
51357200Smargo
51457200Smargo void
sig_report(sig)51557200Smargo sig_report(sig)
51657200Smargo int sig;
51757200Smargo {
51869668Smargo double avg;
51969668Smargo
52065737Sbostic printf("lfs_cleanerd:\t%s%d\n\t\t%s%d\n\t\t%s%d\n\t\t%s%d\n\t\t%s%d\n",
52157200Smargo "blocks_read ", cleaner_stats.blocks_read,
52257200Smargo "blocks_written ", cleaner_stats.blocks_written,
52357200Smargo "segs_cleaned ", cleaner_stats.segs_cleaned,
52457200Smargo "segs_empty ", cleaner_stats.segs_empty,
52557200Smargo "seg_error ", cleaner_stats.segs_error);
52669668Smargo printf("\t\t%s%5.2f\n\t\t%s%5.2f\n",
52769668Smargo "util_tot ", cleaner_stats.util_tot,
52869668Smargo "util_sos ", cleaner_stats.util_sos);
52969668Smargo printf("\t\tavg util: %4.2f std dev: %9.6f\n",
53069668Smargo avg = cleaner_stats.util_tot / cleaner_stats.segs_cleaned,
53169668Smargo cleaner_stats.util_sos / cleaner_stats.segs_cleaned - avg * avg);
53269668Smargo
53369668Smargo
53457200Smargo if (sig == SIGUSR2) {
53560096Sbostic cleaner_stats.blocks_read = 0;
53660096Sbostic cleaner_stats.blocks_written = 0;
53760096Sbostic cleaner_stats.segs_cleaned = 0;
53860096Sbostic cleaner_stats.segs_empty = 0;
53960096Sbostic cleaner_stats.segs_error = 0;
54069668Smargo cleaner_stats.util_tot = 0.0;
54169668Smargo cleaner_stats.util_sos = 0.0;
54257200Smargo }
54357200Smargo if (sig == SIGINT)
54457200Smargo exit(0);
54557200Smargo }
546