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*69668Smargo static char sccsid[] = "@(#)cleanerd.c 8.4 (Berkeley) 05/24/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; 34*69668Smargo int stat_report = 0; 3557200Smargo struct cleaner_stats { 36*69668Smargo double util_tot; 37*69668Smargo 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 */ 48*69668Smargo char sl_bytes; /* bytes in segment */ 4955857Sbostic }; 5055857Sbostic 5155857Sbostic struct tossstruct { 5255857Sbostic struct lfs *lfs; 5355857Sbostic int seg; 5455857Sbostic }; 5555857Sbostic 56*69668Smargo #define CLEAN_BYTES 0x1 57*69668Smargo 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 *))); 68*69668Smargo void clean_fs __P((FS_INFO *, int (*)(FS_INFO *, SEGUSE *), int, long)); 69*69668Smargo 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 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 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; 134*69668Smargo long clean_opts; /* cleaning options */ 135*69668Smargo 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; 141*69668Smargo clean_opts = 0; 142*69668Smargo segs_per_clean = 1; 143*69668Smargo while ((opt = getopt(argc, argv, "bdmn:r:s")) != EOF) { 14457200Smargo switch (opt) { 145*69668Smargo case 'b': /* 146*69668Smargo * Use live bytes to determine 147*69668Smargo * how many segs to clean. 148*69668Smargo */ 149*69668Smargo clean_opts |= CLEAN_BYTES; 15057200Smargo break; 151*69668Smargo case 'd': /* Debug mode. */ 152*69668Smargo nodaemon = 1; 153*69668Smargo break; 154*69668Smargo case 'm': /* Use mmap instead of read/write */ 15557200Smargo do_mmap = 1; 15657200Smargo break; 157*69668Smargo case 'n': /* How many segs to clean at once */ 158*69668Smargo segs_per_clean = atoi(optarg); 15961417Scgd break; 160*69668Smargo case 'r': /* Report every stat_report segments */ 161*69668Smargo stat_report = atoi(optarg); 162*69668Smargo break; 163*69668Smargo case 's': /* small writes */ 164*69668Smargo do_small = 1; 165*69668Smargo 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 */ 202*69668Smargo 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 218*69668Smargo clean_loop(fsp, nsegs, options) 21955857Sbostic FS_INFO *fsp; /* file system information */ 220*69668Smargo int nsegs; 221*69668Smargo long options; 22255857Sbostic { 22355857Sbostic double loadavg[MAXLOADS]; 22455857Sbostic time_t now; 22555857Sbostic u_long max_free_segs; 22655857Sbostic 22755857Sbostic /* 22855857Sbostic * Compute the maximum possible number of free segments, given the 22955857Sbostic * number of free blocks. 23055857Sbostic */ 23155857Sbostic max_free_segs = fsp->fi_statfsp->f_bfree / fsp->fi_lfs.lfs_ssize; 23255857Sbostic 23355857Sbostic /* 23455857Sbostic * We will clean if there are not enough free blocks or total clean 23555857Sbostic * space is less than BUSY_LIM % of possible clean space. 23655857Sbostic */ 23755857Sbostic now = time((time_t *)NULL); 23856181Smargo if (fsp->fi_cip->clean < max_free_segs && 23956181Smargo (fsp->fi_cip->clean <= MIN_SEGS(&fsp->fi_lfs) || 24056181Smargo fsp->fi_cip->clean < max_free_segs * BUSY_LIM)) { 24156656Sbostic printf("Cleaner Running at %s (%d of %d segments available)\n", 24256656Sbostic ctime(&now), fsp->fi_cip->clean, max_free_segs); 243*69668Smargo clean_fs(fsp, cost_benefit, nsegs, options); 24455857Sbostic return (1); 24555857Sbostic } else { 24655857Sbostic /* 24755857Sbostic * We will also clean if the system is reasonably idle and 24855857Sbostic * the total clean space is less then IDLE_LIM % of possible 24955857Sbostic * clean space. 25055857Sbostic */ 25155857Sbostic if (getloadavg(loadavg, MAXLOADS) == -1) { 25255857Sbostic perror("getloadavg: failed\n"); 25355857Sbostic return (-1); 25455857Sbostic } 25555857Sbostic if (loadavg[ONE_MIN] == 0.0 && loadavg[FIVE_MIN] && 25655857Sbostic fsp->fi_cip->clean < max_free_segs * IDLE_LIM) { 257*69668Smargo clean_fs(fsp, cost_benefit, nsegs, options); 25855857Sbostic printf("Cleaner Running at %s (system idle)\n", 25955857Sbostic ctime(&now)); 26055857Sbostic return (1); 26155857Sbostic } 26255857Sbostic } 26355857Sbostic printf("Cleaner Not Running at %s\n", ctime(&now)); 26455857Sbostic return (0); 26555857Sbostic } 26655857Sbostic 26755857Sbostic 26855857Sbostic void 269*69668Smargo clean_fs(fsp, cost_func, nsegs, options) 27055857Sbostic FS_INFO *fsp; /* file system information */ 27155857Sbostic int (*cost_func) __P((FS_INFO *, SEGUSE *)); 272*69668Smargo int nsegs; 273*69668Smargo long options; 27455857Sbostic { 27555857Sbostic struct seglist *segs, *sp; 276*69668Smargo int to_clean, cleaned_bytes; 27755857Sbostic int i; 27855857Sbostic 27965737Sbostic if ((segs = 28065737Sbostic malloc(fsp->fi_lfs.lfs_nseg * sizeof(struct seglist))) == NULL) { 28155857Sbostic err(0, "malloc failed"); 28255857Sbostic return; 28355857Sbostic } 28455857Sbostic i = choose_segments(fsp, segs, cost_func); 28555857Sbostic #ifdef VERBOSE 28656051Sbostic printf("clean_fs: found %d segments to clean in file system %s\n", 28755857Sbostic i, fsp->fi_statfsp->f_mntonname); 28855857Sbostic fflush(stdout); 28955857Sbostic #endif 290*69668Smargo if (i) { 291*69668Smargo /* Check which cleaning algorithm to use. */ 292*69668Smargo if (options & CLEAN_BYTES) { 293*69668Smargo cleaned_bytes = 0; 294*69668Smargo to_clean = nsegs << 295*69668Smargo (fsp->fi_lfs.lfs_segshift + fsp->fi_lfs.lfs_bshift); 296*69668Smargo for (sp = segs; i && cleaned_bytes < to_clean; 297*69668Smargo i--, ++sp) { 298*69668Smargo if (clean_segment(fsp, sp->sl_id) < 0) 299*69668Smargo perror("clean_segment failed"); 300*69668Smargo else if (lfs_segclean(&fsp->fi_statfsp->f_fsid, 301*69668Smargo sp->sl_id) < 0) 302*69668Smargo perror("lfs_segclean failed"); 303*69668Smargo printf("Cleaned segment %d (%d bytes)\n", 304*69668Smargo sp->sl_id, sp->sl_bytes); 305*69668Smargo cleaned_bytes += sp->sl_bytes; 306*69668Smargo } 307*69668Smargo } else 308*69668Smargo for (i = MIN(i, nsegs), sp = segs; i-- ; ++sp) { 309*69668Smargo if (clean_segment(fsp, sp->sl_id) < 0) 310*69668Smargo perror("clean_segment failed"); 311*69668Smargo else if (lfs_segclean(&fsp->fi_statfsp->f_fsid, 312*69668Smargo sp->sl_id) < 0) 313*69668Smargo perror("lfs_segclean failed"); 314*69668Smargo printf("Completed cleaning segment %d\n", sp->sl_id); 315*69668Smargo } 316*69668Smargo } 31755857Sbostic free(segs); 31855857Sbostic } 31955857Sbostic 32055857Sbostic /* 32155857Sbostic * Segment with the highest priority get sorted to the beginning of the 32255857Sbostic * list. This sort assumes that empty segments always have a higher 32355857Sbostic * cost/benefit than any utilized segment. 32455857Sbostic */ 32555857Sbostic int 32655857Sbostic cost_compare(a, b) 32755857Sbostic const void *a; 32855857Sbostic const void *b; 32955857Sbostic { 33055857Sbostic return (((struct seglist *)b)->sl_cost - 33155857Sbostic ((struct seglist *)a)->sl_cost); 33255857Sbostic } 33355857Sbostic 33455857Sbostic 33555857Sbostic /* 33655857Sbostic * Returns the number of segments to be cleaned with the elements of seglist 33755857Sbostic * filled in. 33855857Sbostic */ 33955857Sbostic int 34055857Sbostic choose_segments(fsp, seglist, cost_func) 34155857Sbostic FS_INFO *fsp; 34255857Sbostic struct seglist *seglist; 34355857Sbostic int (*cost_func) __P((FS_INFO *, SEGUSE *)); 34455857Sbostic { 34555857Sbostic struct lfs *lfsp; 34655857Sbostic struct seglist *sp; 34755857Sbostic SEGUSE *sup; 34855857Sbostic int i, nsegs; 34955857Sbostic 35055857Sbostic lfsp = &fsp->fi_lfs; 35155857Sbostic 35255857Sbostic #ifdef VERBOSE 35365737Sbostic (void)printf("Entering choose_segments\n"); 35455857Sbostic #endif 35555857Sbostic dump_super(lfsp); 35655857Sbostic dump_cleaner_info(fsp->fi_cip); 35755857Sbostic 35855857Sbostic for (sp = seglist, i = 0; i < lfsp->lfs_nseg; ++i) { 35955857Sbostic sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, i); 36055857Sbostic PRINT_SEGUSE(sup, i); 36155857Sbostic if (!(sup->su_flags & SEGUSE_DIRTY) || 36255857Sbostic sup->su_flags & SEGUSE_ACTIVE) 36355857Sbostic continue; 36455857Sbostic #ifdef VERBOSE 36565737Sbostic (void)printf("\tchoosing segment %d\n", i); 36655857Sbostic #endif 36755857Sbostic sp->sl_cost = (*cost_func)(fsp, sup); 36855857Sbostic sp->sl_id = i; 369*69668Smargo sp->sl_bytes = sup->su_nbytes; 37055857Sbostic ++sp; 37155857Sbostic } 37255857Sbostic nsegs = sp - seglist; 37355857Sbostic qsort(seglist, nsegs, sizeof(struct seglist), cost_compare); 37455857Sbostic #ifdef VERBOSE 37555857Sbostic (void)printf("Returning %d segments\n", nsegs); 37655857Sbostic #endif 37755857Sbostic return (nsegs); 37855857Sbostic } 37955857Sbostic 38055857Sbostic 38155857Sbostic int 38255857Sbostic clean_segment(fsp, id) 38355857Sbostic FS_INFO *fsp; /* file system information */ 38455857Sbostic int id; /* segment number */ 38555857Sbostic { 38657200Smargo BLOCK_INFO *block_array, *bp; 38755857Sbostic SEGUSE *sp; 38855857Sbostic struct lfs *lfsp; 38955857Sbostic struct tossstruct t; 39055857Sbostic caddr_t seg_buf; 391*69668Smargo double util; 39257200Smargo int num_blocks, maxblocks, clean_blocks; 39355857Sbostic 39455857Sbostic lfsp = &fsp->fi_lfs; 39555857Sbostic sp = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, id); 39655857Sbostic 39755857Sbostic #ifdef VERBOSE 39865737Sbostic (void)printf("cleaning segment %d: contains %lu bytes\n", id, 39955857Sbostic sp->su_nbytes); 40055857Sbostic fflush(stdout); 40155857Sbostic #endif 40255857Sbostic /* XXX could add debugging to verify that segment is really empty */ 40357200Smargo if (sp->su_nbytes == sp->su_nsums * LFS_SUMMARY_SIZE) { 40457200Smargo ++cleaner_stats.segs_empty; 40555857Sbostic return (0); 40657200Smargo } 40755857Sbostic 40855857Sbostic /* map the segment into a buffer */ 40957200Smargo if (mmap_segment(fsp, id, &seg_buf, do_mmap) < 0) { 41055857Sbostic err(0, "mmap_segment failed"); 41157200Smargo ++cleaner_stats.segs_error; 41255857Sbostic return (-1); 41355857Sbostic } 41455857Sbostic /* get a list of blocks that are contained by the segment */ 41555931Sbostic if (lfs_segmapv(fsp, id, seg_buf, &block_array, &num_blocks) < 0) { 41655857Sbostic err(0, "clean_segment: lfs_segmapv failed"); 41757200Smargo ++cleaner_stats.segs_error; 41855857Sbostic return (-1); 41955857Sbostic } 42057200Smargo cleaner_stats.blocks_read += fsp->fi_lfs.lfs_ssize; 42155857Sbostic 42255857Sbostic #ifdef VERBOSE 42365737Sbostic (void)printf("lfs_segmapv returned %d blocks\n", num_blocks); 42465737Sbostic fflush(stdout); 42555857Sbostic #endif 42655857Sbostic 42755857Sbostic /* get the current disk address of blocks contained by the segment */ 42865737Sbostic if (lfs_bmapv(&fsp->fi_statfsp->f_fsid, block_array, num_blocks) < 0) { 42955857Sbostic perror("clean_segment: lfs_bmapv failed\n"); 43057200Smargo ++cleaner_stats.segs_error; 43155857Sbostic return -1; 43255857Sbostic } 43355857Sbostic 43455857Sbostic /* Now toss any blocks not in the current segment */ 43555857Sbostic t.lfs = lfsp; 43655857Sbostic t.seg = id; 43755857Sbostic toss(block_array, &num_blocks, sizeof(BLOCK_INFO), bi_tossold, &t); 43855857Sbostic 43955857Sbostic /* Check if last element should be tossed */ 44055857Sbostic if (num_blocks && bi_tossold(&t, block_array + num_blocks - 1, NULL)) 44155857Sbostic --num_blocks; 44255857Sbostic 44355857Sbostic #ifdef VERBOSE 44455857Sbostic { 44555857Sbostic BLOCK_INFO *_bip; 44655857Sbostic u_long *lp; 44755857Sbostic int i; 44855857Sbostic 44965737Sbostic (void)printf("after bmapv still have %d blocks\n", num_blocks); 45065737Sbostic fflush(stdout); 45155857Sbostic if (num_blocks) 45255857Sbostic printf("BLOCK INFOS\n"); 45355857Sbostic for (_bip = block_array, i=0; i < num_blocks; ++_bip, ++i) { 45455857Sbostic PRINT_BINFO(_bip); 45555857Sbostic lp = (u_long *)_bip->bi_bp; 45655857Sbostic } 45755857Sbostic } 458*69668Smargo 45955857Sbostic #endif 460*69668Smargo ++cleaner_stats.segs_cleaned; 46157200Smargo cleaner_stats.blocks_written += num_blocks; 462*69668Smargo util = ((double)num_blocks / fsp->fi_lfs.lfs_ssize); 463*69668Smargo cleaner_stats.util_tot += util; 464*69668Smargo cleaner_stats.util_sos += util * util; 465*69668Smargo 46657200Smargo if (do_small) 46757200Smargo maxblocks = MAXPHYS / fsp->fi_lfs.lfs_bsize - 1; 46857200Smargo else 46957200Smargo maxblocks = num_blocks; 47057200Smargo 47157200Smargo for (bp = block_array; num_blocks > 0; bp += clean_blocks) { 47257200Smargo clean_blocks = maxblocks < num_blocks ? maxblocks : num_blocks; 47365737Sbostic if (lfs_markv(&fsp->fi_statfsp->f_fsid, 47465737Sbostic bp, clean_blocks) < 0) { 47556051Sbostic err(0, "clean_segment: lfs_markv failed"); 47657200Smargo ++cleaner_stats.segs_error; 47755857Sbostic return (-1); 47855857Sbostic } 47957200Smargo num_blocks -= clean_blocks; 48057200Smargo } 48157200Smargo 48255857Sbostic free(block_array); 48365737Sbostic munmap_segment(fsp, seg_buf, do_mmap); 484*69668Smargo if (stat_report && cleaner_stats.segs_cleaned % stat_report == 0) 485*69668Smargo sig_report(SIGUSR1); 48655857Sbostic return (0); 48755857Sbostic } 48855857Sbostic 48955857Sbostic 49055857Sbostic int 49155857Sbostic bi_tossold(client, a, b) 49255857Sbostic const void *client; 49355857Sbostic const void *a; 49455857Sbostic const void *b; 49555857Sbostic { 49655857Sbostic const struct tossstruct *t; 49755857Sbostic 49855857Sbostic t = (struct tossstruct *)client; 49955857Sbostic 50055857Sbostic return (((BLOCK_INFO *)a)->bi_daddr == LFS_UNUSED_DADDR || 50155857Sbostic datosn(t->lfs, ((BLOCK_INFO *)a)->bi_daddr) != t->seg); 50255857Sbostic } 50357200Smargo 50457200Smargo void 50557200Smargo sig_report(sig) 50657200Smargo int sig; 50757200Smargo { 508*69668Smargo double avg; 509*69668Smargo 51065737Sbostic 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", 51157200Smargo "blocks_read ", cleaner_stats.blocks_read, 51257200Smargo "blocks_written ", cleaner_stats.blocks_written, 51357200Smargo "segs_cleaned ", cleaner_stats.segs_cleaned, 51457200Smargo "segs_empty ", cleaner_stats.segs_empty, 51557200Smargo "seg_error ", cleaner_stats.segs_error); 516*69668Smargo printf("\t\t%s%5.2f\n\t\t%s%5.2f\n", 517*69668Smargo "util_tot ", cleaner_stats.util_tot, 518*69668Smargo "util_sos ", cleaner_stats.util_sos); 519*69668Smargo printf("\t\tavg util: %4.2f std dev: %9.6f\n", 520*69668Smargo avg = cleaner_stats.util_tot / cleaner_stats.segs_cleaned, 521*69668Smargo cleaner_stats.util_sos / cleaner_stats.segs_cleaned - avg * avg); 522*69668Smargo 523*69668Smargo 52457200Smargo if (sig == SIGUSR2) { 52560096Sbostic cleaner_stats.blocks_read = 0; 52660096Sbostic cleaner_stats.blocks_written = 0; 52760096Sbostic cleaner_stats.segs_cleaned = 0; 52860096Sbostic cleaner_stats.segs_empty = 0; 52960096Sbostic cleaner_stats.segs_error = 0; 530*69668Smargo cleaner_stats.util_tot = 0.0; 531*69668Smargo cleaner_stats.util_sos = 0.0; 53257200Smargo } 53357200Smargo if (sig == SIGINT) 53457200Smargo exit(0); 53557200Smargo } 536