⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cleanerd.c

📁 早期freebsd实现
💻 C
字号:
/*- * Copyright (c) 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1992, 1993\n\	The Regents of the University of California.  All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)cleanerd.c	8.2 (Berkeley) 1/13/94";#endif /* not lint */#include <sys/param.h>#include <sys/mount.h>#include <sys/time.h>#include <ufs/ufs/dinode.h>#include <ufs/lfs/lfs.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include "clean.h"char *special = "cleanerd";int do_small = 0;int do_mmap = 0;struct cleaner_stats {	int	blocks_read;	int	blocks_written;	int	segs_cleaned;	int	segs_empty;	int	segs_error;} cleaner_stats;struct seglist { 	int sl_id;	/* segment number */	int sl_cost; 	/* cleaning cost */	char sl_empty;	/* is segment empty */};struct tossstruct {	struct lfs *lfs;	int seg;};/* function prototypes for system calls; not sure where they should go */int	 lfs_segwait __P((fsid_t *, struct timeval *));int	 lfs_segclean __P((fsid_t *, u_long));int	 lfs_bmapv __P((fsid_t *, BLOCK_INFO *, int));int	 lfs_markv __P((fsid_t *, BLOCK_INFO *, int));/* function prototypes */int	 bi_tossold __P((const void *, const void *, const void *));int	 choose_segments __P((FS_INFO *, struct seglist *, 	     int (*)(FS_INFO *, SEGUSE *)));void	 clean_fs __P((FS_INFO	*, int (*)(FS_INFO *, SEGUSE *)));int	 clean_loop __P((FS_INFO *));int	 clean_segment __P((FS_INFO *, int));int	 cost_benefit __P((FS_INFO *, SEGUSE *));int	 cost_compare __P((const void *, const void *));void	 sig_report __P((int));/* * Cleaning Cost Functions: * * These return the cost of cleaning a segment.  The higher the cost value * the better it is to clean the segment, so empty segments have the highest * cost.  (It is probably better to think of this as a priority value * instead). * * This is the cost-benefit policy simulated and described in Rosenblum's * 1991 SOSP paper. */intcost_benefit(fsp, su)	FS_INFO *fsp;		/* file system information */	SEGUSE *su;{	struct lfs *lfsp;	struct timeval t;	int age;	int live;	gettimeofday(&t, NULL);	live = su->su_nbytes;		age = t.tv_sec < su->su_lastmod ? 0 : t.tv_sec - su->su_lastmod;		lfsp = &fsp->fi_lfs;	if (live == 0)		return (t.tv_sec * lblkno(lfsp, seg_size(lfsp)));	else {		/* 		 * from lfsSegUsage.c (Mendel's code).		 * priority calculation is done using INTEGER arithmetic.		 * sizes are in BLOCKS (that is why we use lblkno below).		 * age is in seconds.		 *		 * priority = ((seg_size - live) * age) / (seg_size + live)		 */#ifdef VERBOSE		if (live < 0 || live > seg_size(lfsp)) {			err(0, "Bad segusage count: %d", live);			live = 0;		}#endif		return (lblkno(lfsp, seg_size(lfsp) - live) * age)			/ lblkno(lfsp, seg_size(lfsp) + live);	}}intmain(argc, argv)	int argc;	char *argv[];{	FS_INFO	*fsp;	struct statfs *lstatfsp;	/* file system stats */	struct timeval timeout;		/* sleep timeout */	fsid_t fsid;	int i, nodaemon;	int opt, cmd_err;	char *fs_name;			/* name of filesystem to clean */	extern int optind;	cmd_err = nodaemon = 0;	while ((opt = getopt(argc, argv, "smd")) != EOF) {		switch (opt) {			case 's':	/* small writes */				do_small = 1;				break;			case 'm':				do_mmap = 1;				break;			case 'd':				nodaemon = 1;				break;			default:				++cmd_err;		}	}	argc -= optind;	argv += optind;	if (cmd_err || (argc != 1))		err(1, "usage: lfs_cleanerd [-smd] fs_name");	fs_name = argv[0];	signal(SIGINT, sig_report);	signal(SIGUSR1, sig_report);	signal(SIGUSR2, sig_report);	if (fs_getmntinfo(&lstatfsp, fs_name, MOUNT_LFS) == 0) {		/* didn't find the filesystem */		err(1, "lfs_cleanerd: filesystem %s isn't an LFS!", fs_name);	}	if (!nodaemon)	/* should we become a daemon, chdir to / & close fd's */		if (daemon(0, 0) == -1)			err(1, "lfs_cleanerd: couldn't become a daemon!");	timeout.tv_sec = 5*60; /* five minutes */	timeout.tv_usec = 0;	fsid.val[0] = 0;	fsid.val[1] = 0;	for (fsp = get_fs_info(lstatfsp, do_mmap); ;	    reread_fs_info(fsp, do_mmap)) {		/*		 * clean the filesystem, and, if it needed cleaning		 * (i.e. it returned nonzero) try it again		 * to make sure that some nasty process hasn't just		 * filled the disk system up.		 */		if (clean_loop(fsp))			continue;#ifdef VERBOSE		(void)printf("Cleaner going to sleep.\n");#endif		if (lfs_segwait(&fsid, &timeout) < 0)			err(0, "lfs_segwait: returned error\n");	#ifdef VERBOSE		(void)printf("Cleaner waking up.\n");#endif	}}/* return the number of segments cleaned */intclean_loop(fsp)	FS_INFO	*fsp;	/* file system information */{	double loadavg[MAXLOADS];	time_t	now;	u_long max_free_segs;        /*	 * Compute the maximum possible number of free segments, given the	 * number of free blocks.	 */	max_free_segs = fsp->fi_statfsp->f_bfree / fsp->fi_lfs.lfs_ssize;		/* 	 * We will clean if there are not enough free blocks or total clean	 * space is less than BUSY_LIM % of possible clean space.	 */	now = time((time_t *)NULL);	if (fsp->fi_cip->clean < max_free_segs &&	    (fsp->fi_cip->clean <= MIN_SEGS(&fsp->fi_lfs) ||	    fsp->fi_cip->clean < max_free_segs * BUSY_LIM)) {		printf("Cleaner Running  at %s (%d of %d segments available)\n",		    ctime(&now), fsp->fi_cip->clean, max_free_segs);		clean_fs(fsp, cost_benefit);		return (1);	} else {	        /* 		 * We will also clean if the system is reasonably idle and		 * the total clean space is less then IDLE_LIM % of possible		 * clean space.		 */		if (getloadavg(loadavg, MAXLOADS) == -1) {			perror("getloadavg: failed\n");			return (-1);		}		if (loadavg[ONE_MIN] == 0.0 && loadavg[FIVE_MIN] &&		    fsp->fi_cip->clean < max_free_segs * IDLE_LIM) {		        clean_fs(fsp, cost_benefit);			printf("Cleaner Running  at %s (system idle)\n",			    ctime(&now));			return (1);		}	} 	printf("Cleaner Not Running at %s\n", ctime(&now));	return (0);}voidclean_fs(fsp, cost_func)	FS_INFO	*fsp;	/* file system information */	int (*cost_func) __P((FS_INFO *, SEGUSE *));{	struct seglist *segs, *sp;	int i;	if ((segs =	    malloc(fsp->fi_lfs.lfs_nseg * sizeof(struct seglist))) == NULL) {		err(0, "malloc failed");		return;	}	i = choose_segments(fsp, segs, cost_func);#ifdef VERBOSE	printf("clean_fs: found %d segments to clean in file system %s\n",		i, fsp->fi_statfsp->f_mntonname);	fflush(stdout);#endif	if (i)		for (i = MIN(i, NUM_TO_CLEAN(fsp)), sp = segs; i-- ; ++sp) {			if (clean_segment(fsp, sp->sl_id) < 0)				perror("clean_segment failed");			else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,			    sp->sl_id) < 0)				perror("lfs_segclean failed");			printf("Completed cleaning segment %d\n", sp->sl_id);		}	free(segs);}/* * Segment with the highest priority get sorted to the beginning of the * list.  This sort assumes that empty segments always have a higher * cost/benefit than any utilized segment. */intcost_compare(a, b)	const void *a;	const void *b;{	return (((struct seglist *)b)->sl_cost -	    ((struct seglist *)a)->sl_cost);}/* * Returns the number of segments to be cleaned with the elements of seglist * filled in. */intchoose_segments(fsp, seglist, cost_func)	FS_INFO *fsp;	struct seglist *seglist;	int (*cost_func) __P((FS_INFO *, SEGUSE *));{	struct lfs *lfsp;	struct seglist *sp;	SEGUSE *sup;	int i, nsegs;	lfsp = &fsp->fi_lfs;#ifdef VERBOSE	(void)printf("Entering choose_segments\n");#endif	dump_super(lfsp);	dump_cleaner_info(fsp->fi_cip);	for (sp = seglist, i = 0; i < lfsp->lfs_nseg; ++i) {		sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, i);		 PRINT_SEGUSE(sup, i);		if (!(sup->su_flags & SEGUSE_DIRTY) ||		    sup->su_flags & SEGUSE_ACTIVE)			continue;#ifdef VERBOSE		(void)printf("\tchoosing segment %d\n", i);#endif		sp->sl_cost = (*cost_func)(fsp, sup);		sp->sl_id = i;		sp->sl_empty = sup->su_nbytes ? 0 : 1;		++sp;	}	nsegs = sp - seglist;	qsort(seglist, nsegs, sizeof(struct seglist), cost_compare);#ifdef VERBOSE	(void)printf("Returning %d segments\n", nsegs);#endif	return (nsegs);}intclean_segment(fsp, id)	FS_INFO *fsp;	/* file system information */	int id;		/* segment number */{	BLOCK_INFO *block_array, *bp;	SEGUSE *sp;	struct lfs *lfsp;	struct tossstruct t;	caddr_t seg_buf;	int num_blocks, maxblocks, clean_blocks;	lfsp = &fsp->fi_lfs;	sp = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, id);#ifdef VERBOSE	(void)printf("cleaning segment %d: contains %lu bytes\n", id,	    sp->su_nbytes);	fflush(stdout);#endif	/* XXX could add debugging to verify that segment is really empty */	if (sp->su_nbytes == sp->su_nsums * LFS_SUMMARY_SIZE) {		++cleaner_stats.segs_empty;		return (0);	}	/* map the segment into a buffer */	if (mmap_segment(fsp, id, &seg_buf, do_mmap) < 0) {		err(0, "mmap_segment failed");		++cleaner_stats.segs_error;		return (-1);	}	/* get a list of blocks that are contained by the segment */	if (lfs_segmapv(fsp, id, seg_buf, &block_array, &num_blocks) < 0) {		err(0, "clean_segment: lfs_segmapv failed");		++cleaner_stats.segs_error;		return (-1);	}	cleaner_stats.blocks_read += fsp->fi_lfs.lfs_ssize;#ifdef VERBOSE	(void)printf("lfs_segmapv returned %d blocks\n", num_blocks);	fflush(stdout);#endif	/* get the current disk address of blocks contained by the segment */	if (lfs_bmapv(&fsp->fi_statfsp->f_fsid, block_array, num_blocks) < 0) {		perror("clean_segment: lfs_bmapv failed\n");		++cleaner_stats.segs_error;		return -1;	}	/* Now toss any blocks not in the current segment */	t.lfs = lfsp;	t.seg = id;	toss(block_array, &num_blocks, sizeof(BLOCK_INFO), bi_tossold, &t);	/* Check if last element should be tossed */	if (num_blocks && bi_tossold(&t, block_array + num_blocks - 1, NULL))		--num_blocks;#ifdef VERBOSE	{		BLOCK_INFO *_bip;		u_long *lp;		int i;		(void)printf("after bmapv still have %d blocks\n", num_blocks);		fflush(stdout);		if (num_blocks)			printf("BLOCK INFOS\n");		for (_bip = block_array, i=0; i < num_blocks; ++_bip, ++i) {			PRINT_BINFO(_bip);			lp = (u_long *)_bip->bi_bp;		}	}#endif	cleaner_stats.blocks_written += num_blocks;	if (do_small)		maxblocks = MAXPHYS / fsp->fi_lfs.lfs_bsize - 1;	else		maxblocks = num_blocks;	for (bp = block_array; num_blocks > 0; bp += clean_blocks) {		clean_blocks = maxblocks < num_blocks ? maxblocks : num_blocks;		if (lfs_markv(&fsp->fi_statfsp->f_fsid,		    bp, clean_blocks) < 0) {			err(0, "clean_segment: lfs_markv failed");			++cleaner_stats.segs_error;			return (-1);		}		num_blocks -= clean_blocks;	}			free(block_array);	munmap_segment(fsp, seg_buf, do_mmap);	++cleaner_stats.segs_cleaned;	return (0);}intbi_tossold(client, a, b)	const void *client;	const void *a;	const void *b;{	const struct tossstruct *t;	t = (struct tossstruct *)client;	return (((BLOCK_INFO *)a)->bi_daddr == LFS_UNUSED_DADDR ||	    datosn(t->lfs, ((BLOCK_INFO *)a)->bi_daddr) != t->seg);}voidsig_report(sig)	int sig;{	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",		"blocks_read    ", cleaner_stats.blocks_read,		"blocks_written ", cleaner_stats.blocks_written,		"segs_cleaned   ", cleaner_stats.segs_cleaned,		"segs_empty     ", cleaner_stats.segs_empty,		"seg_error      ", cleaner_stats.segs_error);	if (sig == SIGUSR2) {		cleaner_stats.blocks_read = 0;		cleaner_stats.blocks_written = 0;		cleaner_stats.segs_cleaned = 0;		cleaner_stats.segs_empty = 0;		cleaner_stats.segs_error = 0;	}	if (sig == SIGINT)		exit(0);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -