Home | History | Annotate | Line # | Download | only in lfs_cleanerd
      1  1.33  dholland /*      $NetBSD: coalesce.c,v 1.33 2015/10/10 22:34:46 dholland Exp $  */
      2   1.1  perseant 
      3   1.1  perseant /*-
      4  1.11  perseant  * Copyright (c) 2002, 2005 The NetBSD Foundation, Inc.
      5   1.1  perseant  * All rights reserved.
      6   1.1  perseant  *
      7   1.1  perseant  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1  perseant  * by Konrad E. Schroder <perseant (at) hhhh.org>.
      9   1.1  perseant  *
     10   1.1  perseant  * Redistribution and use in source and binary forms, with or without
     11   1.1  perseant  * modification, are permitted provided that the following conditions
     12   1.1  perseant  * are met:
     13   1.1  perseant  * 1. Redistributions of source code must retain the above copyright
     14   1.1  perseant  *    notice, this list of conditions and the following disclaimer.
     15   1.1  perseant  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  perseant  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  perseant  *    documentation and/or other materials provided with the distribution.
     18   1.1  perseant  *
     19   1.1  perseant  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1  perseant  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1  perseant  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1  perseant  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1  perseant  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1  perseant  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1  perseant  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1  perseant  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1  perseant  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1  perseant  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1  perseant  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1  perseant  */
     31   1.1  perseant 
     32   1.1  perseant #include <sys/param.h>
     33   1.1  perseant #include <sys/mount.h>
     34   1.1  perseant #include <sys/time.h>
     35   1.1  perseant #include <sys/resource.h>
     36   1.1  perseant #include <sys/types.h>
     37   1.1  perseant #include <sys/wait.h>
     38   1.1  perseant #include <sys/mman.h>
     39   1.1  perseant 
     40   1.1  perseant #include <ufs/lfs/lfs.h>
     41   1.1  perseant 
     42   1.1  perseant #include <fcntl.h>
     43   1.1  perseant #include <signal.h>
     44   1.1  perseant #include <stdio.h>
     45   1.1  perseant #include <stdlib.h>
     46   1.1  perseant #include <string.h>
     47   1.1  perseant #include <time.h>
     48   1.1  perseant #include <unistd.h>
     49   1.1  perseant #include <util.h>
     50   1.1  perseant #include <errno.h>
     51   1.1  perseant #include <err.h>
     52  1.26  dholland #include <assert.h>
     53   1.1  perseant 
     54   1.1  perseant #include <syslog.h>
     55   1.1  perseant 
     56  1.11  perseant #include "bufcache.h"
     57  1.11  perseant #include "vnode.h"
     58  1.11  perseant #include "cleaner.h"
     59  1.18     pooka #include "kernelops.h"
     60   1.1  perseant 
     61   1.2  perseant extern int debug, do_mmap;
     62   1.1  perseant 
     63  1.29  dholland /*
     64  1.29  dholland  * XXX return the arg to just int when/if we don't need it for
     65  1.29  dholland  * potentially huge block counts any more.
     66  1.29  dholland  */
     67  1.29  dholland static int
     68  1.29  dholland log2int(intmax_t n)
     69   1.2  perseant {
     70   1.2  perseant 	int log;
     71   1.2  perseant 
     72   1.2  perseant 	log = 0;
     73   1.2  perseant 	while (n > 0) {
     74   1.2  perseant 		++log;
     75  1.11  perseant 		n >>= 1;
     76   1.2  perseant 	}
     77   1.2  perseant 	return log - 1;
     78   1.2  perseant }
     79   1.2  perseant 
     80   1.3  perseant enum coalesce_returncodes {
     81   1.3  perseant 	COALESCE_OK = 0,
     82   1.3  perseant 	COALESCE_NOINODE,
     83   1.3  perseant 	COALESCE_TOOSMALL,
     84   1.3  perseant 	COALESCE_BADSIZE,
     85   1.3  perseant 	COALESCE_BADBLOCKSIZE,
     86   1.3  perseant 	COALESCE_NOMEM,
     87   1.3  perseant 	COALESCE_BADBMAPV,
     88  1.11  perseant 	COALESCE_BADMARKV,
     89   1.3  perseant 	COALESCE_NOTWORTHIT,
     90   1.3  perseant 	COALESCE_NOTHINGLEFT,
     91   1.5      yamt 	COALESCE_EIO,
     92   1.3  perseant 
     93   1.3  perseant 	COALESCE_MAXERROR
     94   1.3  perseant };
     95   1.3  perseant 
     96  1.17     lukem const char *coalesce_return[] = {
     97   1.3  perseant 	"Successfully coalesced",
     98   1.3  perseant 	"File not in use or inode not found",
     99   1.3  perseant 	"Not large enough to coalesce",
    100   1.3  perseant 	"Negative size",
    101   1.3  perseant 	"Not enough blocks to account for size",
    102   1.3  perseant 	"Malloc failed",
    103   1.8  perseant 	"LFCNBMAPV failed",
    104   1.3  perseant 	"Not broken enough to fix",
    105   1.3  perseant 	"Too many blocks not found",
    106   1.3  perseant 	"Too many blocks found in active segments",
    107   1.5      yamt 	"I/O error",
    108   1.3  perseant 
    109   1.3  perseant 	"No such error"
    110   1.3  perseant };
    111   1.3  perseant 
    112  1.32  dholland static union lfs_dinode *
    113  1.11  perseant get_dinode(struct clfs *fs, ino_t ino)
    114  1.11  perseant {
    115  1.11  perseant 	IFILE *ifp;
    116  1.11  perseant 	daddr_t daddr;
    117  1.11  perseant 	struct ubuf *bp;
    118  1.32  dholland 	union lfs_dinode *dip, *r;
    119  1.32  dholland 	unsigned i;
    120  1.11  perseant 
    121  1.11  perseant 	lfs_ientry(&ifp, fs, ino, &bp);
    122  1.31  dholland 	daddr = lfs_if_getdaddr(fs, ifp);
    123  1.14        ad 	brelse(bp, 0);
    124  1.11  perseant 
    125  1.11  perseant 	if (daddr == 0x0)
    126  1.11  perseant 		return NULL;
    127  1.11  perseant 
    128  1.26  dholland 	bread(fs->clfs_devvp, daddr, lfs_sb_getibsize(fs), 0, &bp);
    129  1.32  dholland 	for (i = 0; i < LFS_INOPB(fs); i++) {
    130  1.32  dholland 		dip = DINO_IN_BLOCK(fs, bp->b_data, i);
    131  1.32  dholland 		if (lfs_dino_getinumber(fs, dip) == ino) {
    132  1.32  dholland 			r = malloc(sizeof(*r));
    133  1.19  perseant 			if (r == NULL)
    134  1.19  perseant 				break;
    135  1.32  dholland 			/*
    136  1.32  dholland 			 * Don't just assign the union, as if we're
    137  1.32  dholland 			 * 32-bit and it's the last inode in the block
    138  1.32  dholland 			 * that will run off the end of the buffer.
    139  1.32  dholland 			 */
    140  1.32  dholland 			if (fs->lfs_is64) {
    141  1.32  dholland 				r->u_64 = dip->u_64;
    142  1.32  dholland 			} else {
    143  1.32  dholland 				r->u_32 = dip->u_32;
    144  1.32  dholland 			}
    145  1.14        ad 			brelse(bp, 0);
    146  1.11  perseant 			return r;
    147  1.11  perseant 		}
    148  1.32  dholland 	}
    149  1.14        ad 	brelse(bp, 0);
    150  1.11  perseant 	return NULL;
    151  1.11  perseant }
    152  1.11  perseant 
    153   1.1  perseant /*
    154   1.1  perseant  * Find out if this inode's data blocks are discontinuous; if they are,
    155   1.7  perseant  * rewrite them using markv.  Return the number of inodes rewritten.
    156   1.1  perseant  */
    157  1.11  perseant static int
    158  1.11  perseant clean_inode(struct clfs *fs, ino_t ino)
    159   1.1  perseant {
    160   1.7  perseant 	BLOCK_INFO *bip = NULL, *tbip;
    161  1.11  perseant 	CLEANERINFO cip;
    162  1.11  perseant 	struct ubuf *bp;
    163  1.32  dholland 	union lfs_dinode *dip;
    164  1.11  perseant 	struct clfs_seguse *sup;
    165  1.11  perseant 	struct lfs_fcntl_markv /* {
    166  1.11  perseant 		BLOCK_INFO *blkiov;
    167  1.11  perseant 		int blkcnt;
    168  1.11  perseant 	} */ lim;
    169  1.11  perseant 	daddr_t toff;
    170  1.29  dholland 	int noff;
    171  1.29  dholland 	blkcnt_t i, nb, onb;
    172  1.11  perseant 	int retval;
    173   1.1  perseant 	int bps;
    174   1.1  perseant 
    175  1.11  perseant 	dip = get_dinode(fs, ino);
    176   1.1  perseant 	if (dip == NULL)
    177   1.3  perseant 		return COALESCE_NOINODE;
    178   1.1  perseant 
    179   1.7  perseant 	/* Compute file block size, set up for bmapv */
    180  1.32  dholland 	onb = nb = lfs_lblkno(fs, lfs_dino_getsize(fs, dip));
    181   1.2  perseant 
    182   1.2  perseant 	/* XXX for now, don't do any file small enough to have fragments */
    183  1.21  dholland 	if (nb < ULFS_NDADDR) {
    184  1.12  christos 		free(dip);
    185   1.3  perseant 		return COALESCE_TOOSMALL;
    186  1.12  christos 	}
    187   1.2  perseant 
    188   1.2  perseant 	/* Sanity checks */
    189  1.17     lukem #if 0	/* di_size is uint64_t -- this is a noop */
    190  1.32  dholland 	if (lfs_dino_getsize(fs, dip) < 0) {
    191  1.32  dholland 		dlog("ino %d, negative size (%" PRId64 ")", ino,
    192  1.32  dholland 		     lfs_dino_getsize(fs, dip));
    193  1.12  christos 		free(dip);
    194   1.3  perseant 		return COALESCE_BADSIZE;
    195   1.2  perseant 	}
    196  1.17     lukem #endif
    197  1.32  dholland 	if (nb > lfs_dino_getblocks(fs, dip)) {
    198  1.29  dholland 		dlog("ino %ju, computed blocks %jd > held blocks %ju",
    199  1.29  dholland 		     (uintmax_t)ino, (intmax_t)nb,
    200  1.32  dholland 		     (uintmax_t)lfs_dino_getblocks(fs, dip));
    201  1.12  christos 		free(dip);
    202   1.3  perseant 		return COALESCE_BADBLOCKSIZE;
    203   1.1  perseant 	}
    204   1.2  perseant 
    205  1.29  dholland 	/*
    206  1.29  dholland 	 * XXX: We should really coalesce really large files in
    207  1.29  dholland 	 * chunks, as there's substantial diminishing returns and
    208  1.29  dholland 	 * mallocing huge amounts of memory just to get those returns
    209  1.29  dholland 	 * is pretty silly. But that requires a big rework of this
    210  1.29  dholland 	 * code. (On the plus side though then we can stop worrying
    211  1.29  dholland 	 * about block counts > 2^31.)
    212  1.29  dholland 	 */
    213  1.29  dholland 
    214  1.29  dholland 	/* ugh, no DADDR_T_MAX */
    215  1.29  dholland 	__CTASSERT(sizeof(daddr_t) == sizeof(int64_t));
    216  1.29  dholland 	if (nb > INT64_MAX / sizeof(BLOCK_INFO)) {
    217  1.29  dholland 		syslog(LOG_WARNING, "ino %ju, %jd blocks: array too large\n",
    218  1.29  dholland 		       (uintmax_t)ino, (uintmax_t)nb);
    219  1.29  dholland 		free(dip);
    220  1.29  dholland 		return COALESCE_NOMEM;
    221  1.29  dholland 	}
    222  1.29  dholland 
    223   1.7  perseant 	bip = (BLOCK_INFO *)malloc(sizeof(BLOCK_INFO) * nb);
    224   1.1  perseant 	if (bip == NULL) {
    225  1.29  dholland 		syslog(LOG_WARNING, "ino %llu, %jd blocks: %s\n",
    226  1.29  dholland 		    (unsigned long long)ino, (intmax_t)nb,
    227  1.29  dholland 		    strerror(errno));
    228  1.12  christos 		free(dip);
    229   1.3  perseant 		return COALESCE_NOMEM;
    230   1.1  perseant 	}
    231   1.1  perseant 	for (i = 0; i < nb; i++) {
    232   1.7  perseant 		memset(bip + i, 0, sizeof(BLOCK_INFO));
    233   1.1  perseant 		bip[i].bi_inode = ino;
    234   1.1  perseant 		bip[i].bi_lbn = i;
    235  1.32  dholland 		bip[i].bi_version = lfs_dino_getgen(fs, dip);
    236   1.1  perseant 		/* Don't set the size, but let lfs_bmap fill it in */
    237   1.1  perseant 	}
    238  1.29  dholland 	/*
    239  1.29  dholland 	 * The kernel also contains this check; but as lim.blkcnt is
    240  1.29  dholland 	 * only 32 bits wide, we need to check ourselves too in case
    241  1.29  dholland 	 * we'd otherwise truncate a value > 2^31, as that might
    242  1.29  dholland 	 * succeed and create bizarre results.
    243  1.29  dholland 	 */
    244  1.29  dholland 	if (nb > LFS_MARKV_MAXBLKCNT) {
    245  1.29  dholland 		syslog(LOG_WARNING, "%s: coalesce: LFCNBMAPV: Too large\n",
    246  1.29  dholland 		       lfs_sb_getfsmnt(fs));
    247  1.29  dholland 		retval = COALESCE_BADBMAPV;
    248  1.29  dholland 		goto out;
    249  1.29  dholland 	}
    250  1.11  perseant 	lim.blkiov = bip;
    251  1.11  perseant 	lim.blkcnt = nb;
    252  1.18     pooka 	if (kops.ko_fcntl(fs->clfs_ifilefd, LFCNBMAPV, &lim) < 0) {
    253  1.11  perseant 		syslog(LOG_WARNING, "%s: coalesce: LFCNBMAPV: %m",
    254  1.26  dholland 		       lfs_sb_getfsmnt(fs));
    255   1.5      yamt 		retval = COALESCE_BADBMAPV;
    256   1.5      yamt 		goto out;
    257   1.5      yamt 	}
    258   1.5      yamt #if 0
    259   1.5      yamt 	for (i = 0; i < nb; i++) {
    260  1.29  dholland 		printf("bi_size = %d, bi_ino = %ju, "
    261  1.29  dholland 		    "bi_lbn = %jd, bi_daddr = %jd\n",
    262  1.29  dholland 		    bip[i].bi_size, (uintmax_t)bip[i].bi_inode,
    263  1.29  dholland 		    (intmax_t)bip[i].bi_lbn,
    264  1.29  dholland 		    (intmax_t)bip[i].bi_daddr);
    265   1.1  perseant 	}
    266   1.5      yamt #endif
    267  1.29  dholland 	noff = 0;
    268  1.29  dholland 	toff = 0;
    269   1.1  perseant 	for (i = 1; i < nb; i++) {
    270  1.28  dholland 		if (bip[i].bi_daddr != bip[i - 1].bi_daddr + lfs_sb_getfrag(fs))
    271   1.1  perseant 			++noff;
    272  1.33  dholland 		toff += llabs(bip[i].bi_daddr - bip[i - 1].bi_daddr
    273  1.28  dholland 		    - lfs_sb_getfrag(fs)) >> lfs_sb_getfbshift(fs);
    274   1.1  perseant 	}
    275   1.1  perseant 
    276   1.1  perseant 	/*
    277   1.1  perseant 	 * If this file is not discontinuous, there's no point in rewriting it.
    278  1.11  perseant 	 *
    279  1.11  perseant 	 * Explicitly allow a certain amount of discontinuity, since large
    280  1.11  perseant 	 * files will be broken among segments and medium-sized files
    281  1.11  perseant 	 * can have a break or two and it's okay.
    282   1.1  perseant 	 */
    283   1.2  perseant 	if (nb <= 1 || noff == 0 || noff < log2int(nb) ||
    284  1.23  christos 	    lfs_segtod(fs, noff) * 2 < nb) {
    285   1.5      yamt 		retval = COALESCE_NOTWORTHIT;
    286   1.5      yamt 		goto out;
    287   1.1  perseant 	} else if (debug)
    288  1.10  christos 		syslog(LOG_DEBUG, "ino %llu total discontinuity "
    289  1.29  dholland 		    "%d (%jd) for %jd blocks", (unsigned long long)ino,
    290  1.29  dholland 		    noff, (intmax_t)toff, (intmax_t)nb);
    291   1.1  perseant 
    292   1.1  perseant 	/* Search for blocks in active segments; don't move them. */
    293   1.1  perseant 	for (i = 0; i < nb; i++) {
    294   1.1  perseant 		if (bip[i].bi_daddr <= 0)
    295   1.1  perseant 			continue;
    296  1.23  christos 		sup = &fs->clfs_segtab[lfs_dtosn(fs, bip[i].bi_daddr)];
    297  1.11  perseant 		if (sup->flags & SEGUSE_ACTIVE)
    298   1.1  perseant 			bip[i].bi_daddr = LFS_UNUSED_DADDR; /* 0 */
    299   1.1  perseant 	}
    300  1.11  perseant 
    301  1.11  perseant 	/*
    302  1.11  perseant 	 * Get rid of any blocks we've marked dead.  If this is an older
    303  1.11  perseant 	 * kernel that doesn't have bmapv fill in the block sizes, we'll
    304  1.11  perseant 	 * toss everything here.
    305   1.1  perseant 	 */
    306  1.11  perseant 	onb = nb;
    307  1.13  perseant 	toss_old_blocks(fs, &bip, &nb, NULL);
    308  1.11  perseant 	nb = i;
    309   1.2  perseant 
    310   1.1  perseant 	/*
    311   1.2  perseant 	 * We may have tossed enough blocks that it is no longer worthwhile
    312   1.2  perseant 	 * to rewrite this inode.
    313   1.1  perseant 	 */
    314  1.11  perseant 	if (nb == 0 || onb - nb > log2int(onb)) {
    315   1.3  perseant 		if (debug)
    316   1.3  perseant 			syslog(LOG_DEBUG, "too many blocks tossed, not rewriting");
    317  1.11  perseant 		retval = COALESCE_NOTHINGLEFT;
    318  1.11  perseant 		goto out;
    319   1.1  perseant 	}
    320   1.1  perseant 
    321  1.11  perseant 	/*
    322   1.1  perseant 	 * We are going to rewrite this inode.
    323   1.1  perseant 	 * For any remaining blocks, read in their contents.
    324   1.1  perseant 	 */
    325   1.1  perseant 	for (i = 0; i < nb; i++) {
    326   1.1  perseant 		bip[i].bi_bp = malloc(bip[i].bi_size);
    327   1.5      yamt 		if (bip[i].bi_bp == NULL) {
    328  1.29  dholland 			syslog(LOG_WARNING, "allocate block buffer size=%d: %s\n",
    329  1.29  dholland 			    bip[i].bi_size, strerror(errno));
    330   1.5      yamt 			retval = COALESCE_NOMEM;
    331   1.5      yamt 			goto out;
    332   1.5      yamt 		}
    333  1.11  perseant 
    334  1.18     pooka 		if (kops.ko_pread(fs->clfs_devfd, bip[i].bi_bp, bip[i].bi_size,
    335  1.23  christos 			  lfs_fsbtob(fs, bip[i].bi_daddr)) < 0) {
    336   1.5      yamt 			retval = COALESCE_EIO;
    337   1.5      yamt 			goto out;
    338   1.5      yamt 		}
    339   1.1  perseant 	}
    340   1.1  perseant 	if (debug)
    341  1.29  dholland 		syslog(LOG_DEBUG, "ino %ju markv %jd blocks",
    342  1.29  dholland 		    (uintmax_t)ino, (intmax_t)nb);
    343   1.1  perseant 
    344   1.2  perseant 	/*
    345   1.2  perseant 	 * Write in segment-sized chunks.  If at any point we'd write more
    346   1.2  perseant 	 * than half of the available segments, sleep until that's not
    347   1.2  perseant 	 * true any more.
    348  1.29  dholland 	 *
    349  1.29  dholland 	 * XXX the pointer arithmetic in this loop is illegal; replace
    350  1.29  dholland 	 * TBIP with an integer (blkcnt_t) offset.
    351   1.2  perseant 	 */
    352  1.23  christos 	bps = lfs_segtod(fs, 1);
    353   1.1  perseant 	for (tbip = bip; tbip < bip + nb; tbip += bps) {
    354  1.11  perseant 		do {
    355  1.28  dholland 			bread(fs->lfs_ivnode, 0, lfs_sb_getbsize(fs), 0, &bp);
    356  1.11  perseant 			cip = *(CLEANERINFO *)bp->b_data;
    357  1.14        ad 			brelse(bp, B_INVAL);
    358  1.11  perseant 
    359  1.30  dholland 			if (lfs_ci_getclean(fs, &cip) < 4) /* XXX magic number 4 */
    360  1.18     pooka 				kops.ko_fcntl(fs->clfs_ifilefd,
    361  1.18     pooka 				    LFCNSEGWAIT, NULL);
    362  1.30  dholland 		} while (lfs_ci_getclean(fs, &cip) < 4);
    363  1.11  perseant 
    364  1.29  dholland 		/*
    365  1.29  dholland 		 * Note that although lim.blkcnt is 32 bits wide, bps
    366  1.29  dholland 		 * (which is blocks-per-segment) is < 2^32 so the
    367  1.29  dholland 		 * value assigned here is always in range.
    368  1.29  dholland 		 */
    369  1.11  perseant 		lim.blkiov = tbip;
    370  1.11  perseant 		lim.blkcnt = (tbip + bps < bip + nb ? bps : nb % bps);
    371  1.18     pooka 		if (kops.ko_fcntl(fs->clfs_ifilefd, LFCNMARKV, &lim) < 0) {
    372  1.11  perseant 			retval = COALESCE_BADMARKV;
    373  1.11  perseant 			goto out;
    374   1.2  perseant 		}
    375   1.1  perseant 	}
    376   1.1  perseant 
    377   1.5      yamt 	retval = COALESCE_OK;
    378   1.5      yamt out:
    379  1.11  perseant 	free(dip);
    380   1.5      yamt 	if (bip) {
    381   1.5      yamt 		for (i = 0; i < onb; i++)
    382   1.5      yamt 			if (bip[i].bi_bp)
    383   1.5      yamt 				free(bip[i].bi_bp);
    384   1.5      yamt 		free(bip);
    385   1.5      yamt 	}
    386   1.5      yamt 	return retval;
    387   1.1  perseant }
    388   1.1  perseant 
    389   1.1  perseant /*
    390   1.1  perseant  * Try coalescing every inode in the filesystem.
    391   1.1  perseant  * Return the number of inodes actually altered.
    392   1.1  perseant  */
    393  1.11  perseant int clean_all_inodes(struct clfs *fs)
    394   1.1  perseant {
    395  1.11  perseant 	int i, r, maxino;
    396   1.3  perseant 	int totals[COALESCE_MAXERROR];
    397  1.11  perseant 	struct stat st;
    398   1.1  perseant 
    399   1.3  perseant 	memset(totals, 0, sizeof(totals));
    400  1.11  perseant 
    401  1.11  perseant 	fstat(fs->clfs_ifilefd, &st);
    402  1.26  dholland 	maxino = lfs_sb_getifpb(fs) * (st.st_size >> lfs_sb_getbshift(fs)) -
    403  1.25  dholland 		lfs_sb_getsegtabsz(fs) - lfs_sb_getcleansz(fs);
    404  1.11  perseant 
    405  1.11  perseant 	for (i = 0; i < maxino; i++) {
    406  1.11  perseant 		r = clean_inode(fs, i);
    407   1.3  perseant 		++totals[r];
    408   1.1  perseant 	}
    409   1.3  perseant 
    410   1.3  perseant 	for (i = 0; i < COALESCE_MAXERROR; i++)
    411   1.3  perseant 		if (totals[i])
    412   1.3  perseant 			syslog(LOG_DEBUG, "%s: %d", coalesce_return[i],
    413  1.11  perseant 			       totals[i]);
    414  1.11  perseant 
    415   1.3  perseant 	return totals[COALESCE_OK];
    416   1.1  perseant }
    417   1.1  perseant 
    418  1.11  perseant /*
    419  1.11  perseant  * Fork a child process to coalesce this fs.
    420  1.11  perseant  */
    421  1.11  perseant int
    422  1.11  perseant fork_coalesce(struct clfs *fs)
    423   1.1  perseant {
    424   1.1  perseant 	static pid_t childpid;
    425   1.2  perseant 	int num;
    426   1.2  perseant 
    427  1.11  perseant 	/*
    428  1.11  perseant 	 * If already running a coalescing child, don't start a new one.
    429  1.11  perseant 	 */
    430   1.1  perseant 	if (childpid) {
    431  1.11  perseant 		if (waitpid(childpid, NULL, WNOHANG) == childpid)
    432   1.1  perseant 			childpid = 0;
    433   1.1  perseant 	}
    434   1.1  perseant 	if (childpid && kill(childpid, 0) >= 0) {
    435   1.1  perseant 		/* already running a coalesce process */
    436   1.2  perseant 		if (debug)
    437   1.2  perseant 			syslog(LOG_DEBUG, "coalescing already in progress");
    438   1.1  perseant 		return 0;
    439   1.1  perseant 	}
    440  1.11  perseant 
    441  1.11  perseant 	/*
    442  1.11  perseant 	 * Fork a child and let the child coalease
    443  1.11  perseant 	 */
    444   1.1  perseant 	childpid = fork();
    445   1.1  perseant 	if (childpid < 0) {
    446  1.26  dholland 		syslog(LOG_ERR, "%s: fork to coaleasce: %m", lfs_sb_getfsmnt(fs));
    447   1.1  perseant 		return 0;
    448   1.1  perseant 	} else if (childpid == 0) {
    449  1.11  perseant 		syslog(LOG_NOTICE, "%s: new coalescing process, pid %d",
    450  1.26  dholland 		       lfs_sb_getfsmnt(fs), getpid());
    451  1.11  perseant 		num = clean_all_inodes(fs);
    452  1.11  perseant 		syslog(LOG_NOTICE, "%s: coalesced %d discontiguous inodes",
    453  1.26  dholland 		       lfs_sb_getfsmnt(fs), num);
    454   1.1  perseant 		exit(0);
    455   1.1  perseant 	}
    456  1.11  perseant 
    457   1.1  perseant 	return 0;
    458   1.1  perseant }
    459