Remove lfs_cleanerd
This commit is contained in:
parent
4f4a34fffa
commit
55d6f63f1c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=32892
@ -1,11 +0,0 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
# $Id: Makefile,v 1.7 1997/02/22 14:21:43 peter Exp $
|
||||
|
||||
PROG= lfs_cleanerd
|
||||
CFLAGS+=-I${.CURDIR}/../../sys/ufs/lfs -I${.CURDIR} ${DEBUG}
|
||||
MAN8= lfs_cleanerd.8
|
||||
SRCS= cleanerd.c lfs_cksum.c library.c misc.c print.c
|
||||
|
||||
.PATH: ${.CURDIR}/../../sys/ufs/lfs
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,169 +0,0 @@
|
||||
/*-
|
||||
* 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.
|
||||
*
|
||||
* @(#)clean.h 8.2 (Berkeley) 5/4/95
|
||||
* $Id: clean.h,v 1.6 1997/02/22 14:21:44 peter Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* The LFS user-level library will be used when writing cleaners and
|
||||
* checkers for LFS file systems. It will have facilities for finding
|
||||
* and parsing LFS segments.
|
||||
*/
|
||||
|
||||
#define DUMP_SUM_HEADER 0x0001
|
||||
#define DUMP_INODE_ADDRS 0x0002
|
||||
#define DUMP_FINFOS 0x0004
|
||||
#define DUMP_ALL 0xFFFF
|
||||
|
||||
#define IFILE_NAME "ifile"
|
||||
|
||||
/*
|
||||
* Cleaner parameters
|
||||
* BUSY_LIM: lower bound of the number of segments currently available
|
||||
* as a percentage of the total number of free segments possibly
|
||||
* available.
|
||||
* IDLE_LIM: Same as BUSY_LIM but used when the system is idle.
|
||||
* MIN_SEGS: Minimum number of segments you should always have.
|
||||
* I have no idea what this should be, but it should probably
|
||||
* be a function of lfsp.
|
||||
* NUM_TO_CLEAN: Number of segments to clean at once. Again, this
|
||||
* should probably be based on the file system size and how
|
||||
* full or empty the segments being cleaned are.
|
||||
*/
|
||||
|
||||
#define BUSY_LIM 0.50
|
||||
#define IDLE_LIM 0.90
|
||||
|
||||
#define MIN_SEGS(lfsp) (5)
|
||||
#define NUM_TO_CLEAN(fsp) (1)
|
||||
|
||||
#define MAXLOADS 3
|
||||
#define ONE_MIN 0
|
||||
#define FIVE_MIN 1
|
||||
#define FIFTEEN_MIN 2
|
||||
|
||||
typedef struct fs_info {
|
||||
struct statfs *fi_statfsp; /* fsstat info from getfsstat */
|
||||
struct lfs fi_lfs; /* superblock */
|
||||
CLEANERINFO *fi_cip; /* Cleaner info from ifile */
|
||||
SEGUSE *fi_segusep; /* segment usage table (from ifile) */
|
||||
IFILE *fi_ifilep; /* ifile table (from ifile) */
|
||||
u_long fi_daddr_shift; /* shift to get byte offset of daddr */
|
||||
u_long fi_ifile_count; /* # entries in the ifile table */
|
||||
off_t fi_ifile_length; /* length of the ifile */
|
||||
} FS_INFO;
|
||||
|
||||
/*
|
||||
* XXX: size (in bytes) of a segment
|
||||
* should lfs_bsize be fsbtodb(fs,1), blksize(fs), or lfs_dsize?
|
||||
*/
|
||||
#define seg_size(fs) ((fs)->lfs_ssize << (fs)->lfs_bshift)
|
||||
|
||||
/* daddr -> byte offset */
|
||||
#define datobyte(fs, da) ((da) << (fs)->fi_daddr_shift)
|
||||
#define bytetoda(fs, byte) ((byte) >> (fs)->fi_daddr_shift)
|
||||
|
||||
#define CLEANSIZE(fsp) (fsp->fi_lfs.lfs_cleansz << fsp->fi_lfs.lfs_bshift)
|
||||
#define SEGTABSIZE(fsp) (fsp->fi_lfs.lfs_segtabsz << fsp->fi_lfs.lfs_bshift)
|
||||
|
||||
#define IFILE_ENTRY(fs, if, i) \
|
||||
((IFILE *)((caddr_t)(if) + ((i) / (fs)->lfs_ifpb << (fs)->lfs_bshift)) \
|
||||
+ (i) % (fs)->lfs_ifpb)
|
||||
|
||||
#define SEGUSE_ENTRY(fs, su, i) \
|
||||
((SEGUSE *)((caddr_t)(su) + (fs)->lfs_bsize * ((i) / (fs)->lfs_sepb)) +\
|
||||
(i) % (fs)->lfs_sepb)
|
||||
|
||||
__BEGIN_DECLS
|
||||
int dump_summary __P((struct lfs *, SEGSUM *, u_long, daddr_t **));
|
||||
void err __P((const int, const char *, ...));
|
||||
int fs_getmntinfo __P((struct statfs **, char *, char *));
|
||||
int get __P((int, off_t, void *, size_t));
|
||||
FS_INFO *get_fs_info __P((struct statfs *, int));
|
||||
int lfs_segmapv __P((FS_INFO *, int, caddr_t, BLOCK_INFO **, int *));
|
||||
int mmap_segment __P((FS_INFO *, int, caddr_t *, int));
|
||||
void munmap_segment __P((FS_INFO *, caddr_t, int));
|
||||
void reread_fs_info __P((FS_INFO *, int));
|
||||
void toss __P((void *, int *, size_t,
|
||||
int (*)(const void *, const void *, const void *), void *));
|
||||
|
||||
/*
|
||||
* USEFUL DEBUGGING FUNCTIONS:
|
||||
*/
|
||||
#ifdef VERBOSE
|
||||
#define PRINT_FINFO(fp, ip) { \
|
||||
(void)printf(" %s %s%d version %d nblocks %d\n", \
|
||||
(ip)->if_version > (fp)->fi_version ? "TOSSING" : "KEEPING", \
|
||||
"FINFO for inode: ", (fp)->fi_ino, \
|
||||
(fp)->fi_version, (fp)->fi_nblocks); \
|
||||
fflush(stdout); \
|
||||
}
|
||||
|
||||
#define PRINT_INODE(b, bip) { \
|
||||
(void) printf("\t%s inode: %d daddr: 0x%lx create: %s\n", \
|
||||
b ? "KEEPING" : "TOSSING", (bip)->bi_inode, (bip)->bi_daddr, \
|
||||
ctime((time_t *)&(bip)->bi_segcreate)); \
|
||||
fflush(stdout); \
|
||||
}
|
||||
|
||||
#define PRINT_BINFO(bip) { \
|
||||
(void)printf("\tinode: %d lbn: %d daddr: 0x%lx create: %s\n", \
|
||||
(bip)->bi_inode, (bip)->bi_lbn, (bip)->bi_daddr, \
|
||||
ctime((time_t *)&(bip)->bi_segcreate)); \
|
||||
fflush(stdout); \
|
||||
}
|
||||
|
||||
#define PRINT_SEGUSE(sup, n) { \
|
||||
(void)printf("Segment %d nbytes=%lu\tflags=%c%c%c ninos=%d nsums=%d lastmod: %s\n", \
|
||||
n, (sup)->su_nbytes, \
|
||||
(sup)->su_flags & SEGUSE_DIRTY ? 'D' : 'C', \
|
||||
(sup)->su_flags & SEGUSE_ACTIVE ? 'A' : ' ', \
|
||||
(sup)->su_flags & SEGUSE_SUPERBLOCK ? 'S' : ' ', \
|
||||
(sup)->su_ninos, (sup)->su_nsums, \
|
||||
ctime((time_t *)&(sup)->su_lastmod)); \
|
||||
fflush(stdout); \
|
||||
}
|
||||
|
||||
void dump_super __P((struct lfs *));
|
||||
void dump_cleaner_info __P((void *));
|
||||
void print_SEGSUM __P(( struct lfs *, SEGSUM *));
|
||||
void print_CLEANERINFO __P((CLEANERINFO *));
|
||||
#else
|
||||
#define PRINT_FINFO(fp, ip)
|
||||
#define PRINT_INODE(b, bip)
|
||||
#define PRINT_BINFO(bip)
|
||||
#define PRINT_SEGUSE(sup, n)
|
||||
#define dump_cleaner_info(cip)
|
||||
#define dump_super(lfsp)
|
||||
#endif
|
||||
__END_DECLS
|
@ -1,584 +0,0 @@
|
||||
/*-
|
||||
* 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 lint
|
||||
static const char copyright[] =
|
||||
"@(#) Copyright (c) 1992, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)cleanerd.c 8.5 (Berkeley) 6/10/95";
|
||||
#endif
|
||||
static const char rcsid[] =
|
||||
"$Id: cleanerd.c,v 1.8 1997/11/24 07:26:59 charnier Exp $";
|
||||
#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 <err.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "clean.h"
|
||||
int do_small = 0;
|
||||
int do_mmap = 0;
|
||||
int stat_report = 0;
|
||||
struct cleaner_stats {
|
||||
double util_tot;
|
||||
double util_sos;
|
||||
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_bytes; /* bytes in segment */
|
||||
};
|
||||
|
||||
struct tossstruct {
|
||||
struct lfs *lfs;
|
||||
int seg;
|
||||
};
|
||||
|
||||
#define CLEAN_BYTES 0x1
|
||||
|
||||
/* 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, long));
|
||||
int clean_loop __P((FS_INFO *, int, long));
|
||||
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));
|
||||
static void usage __P((void));
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
int
|
||||
cost_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)) {
|
||||
warnx("bad segusage count: %d", live);
|
||||
live = 0;
|
||||
}
|
||||
#endif
|
||||
return (lblkno(lfsp, seg_size(lfsp) - live) * age)
|
||||
/ lblkno(lfsp, seg_size(lfsp) + live);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
FS_INFO *fsp;
|
||||
struct statfs *lstatfsp; /* file system stats */
|
||||
struct timeval timeout; /* sleep timeout */
|
||||
fsid_t fsid;
|
||||
long clean_opts; /* cleaning options */
|
||||
int nodaemon, segs_per_clean;
|
||||
int opt, cmd_err;
|
||||
char *fs_name; /* name of filesystem to clean */
|
||||
|
||||
cmd_err = nodaemon = 0;
|
||||
clean_opts = 0;
|
||||
segs_per_clean = 1;
|
||||
while ((opt = getopt(argc, argv, "bdmn:r:s")) != -1) {
|
||||
switch (opt) {
|
||||
case 'b': /*
|
||||
* Use live bytes to determine
|
||||
* how many segs to clean.
|
||||
*/
|
||||
clean_opts |= CLEAN_BYTES;
|
||||
break;
|
||||
case 'd': /* Debug mode. */
|
||||
nodaemon = 1;
|
||||
break;
|
||||
case 'm': /* Use mmap instead of read/write */
|
||||
do_mmap = 1;
|
||||
break;
|
||||
case 'n': /* How many segs to clean at once */
|
||||
segs_per_clean = atoi(optarg);
|
||||
break;
|
||||
case 'r': /* Report every stat_report segments */
|
||||
stat_report = atoi(optarg);
|
||||
break;
|
||||
case 's': /* small writes */
|
||||
do_small = 1;
|
||||
break;
|
||||
default:
|
||||
++cmd_err;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (cmd_err || (argc != 1))
|
||||
usage();
|
||||
|
||||
fs_name = argv[0];
|
||||
|
||||
signal(SIGINT, sig_report);
|
||||
signal(SIGUSR1, sig_report);
|
||||
signal(SIGUSR2, sig_report);
|
||||
if (fs_getmntinfo(&lstatfsp, fs_name, "lfs") == 0) {
|
||||
/* didn't find the filesystem */
|
||||
errx(1, "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)
|
||||
errx(1, "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, segs_per_clean, clean_opts))
|
||||
continue;
|
||||
|
||||
#ifdef VERBOSE
|
||||
(void)printf("Cleaner going to sleep.\n");
|
||||
#endif
|
||||
if (lfs_segwait(&fsid, &timeout) < 0)
|
||||
warnx("lfs_segwait: returned error");
|
||||
#ifdef VERBOSE
|
||||
(void)printf("Cleaner waking up.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "usage: lfs_cleanerd [-smd] fs_name\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* return the number of segments cleaned */
|
||||
int
|
||||
clean_loop(fsp, nsegs, options)
|
||||
FS_INFO *fsp; /* file system information */
|
||||
int nsegs;
|
||||
long options;
|
||||
{
|
||||
double loadavg[MAXLOADS];
|
||||
time_t now;
|
||||
u_long max_free_segs;
|
||||
u_long db_per_seg;
|
||||
|
||||
/*
|
||||
* Compute the maximum possible number of free segments, given the
|
||||
* number of free blocks.
|
||||
*/
|
||||
db_per_seg = fsbtodb(&fsp->fi_lfs, fsp->fi_lfs.lfs_ssize);
|
||||
max_free_segs = fsp->fi_lfs.lfs_bfree / db_per_seg;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
#ifdef VERBOSE
|
||||
printf("db_er_seg = %d max_free_segs = %d, bfree = %d avail = %d ",
|
||||
db_per_seg, max_free_segs, fsp->fi_lfs.lfs_bfree,
|
||||
fsp->fi_lfs.lfs_avail);
|
||||
printf("clean = %d\n", fsp->fi_cip->clean);
|
||||
#endif
|
||||
if ((fsp->fi_lfs.lfs_bfree - fsp->fi_lfs.lfs_avail > db_per_seg &&
|
||||
fsp->fi_lfs.lfs_avail < db_per_seg) ||
|
||||
(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 %ld segments available)\n",
|
||||
ctime(&now), fsp->fi_cip->clean, max_free_segs);
|
||||
clean_fs(fsp, cost_benefit, nsegs, options);
|
||||
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) {
|
||||
warn("getloadavg failed");
|
||||
return (-1);
|
||||
}
|
||||
if (loadavg[ONE_MIN] == 0.2 && loadavg[FIVE_MIN] &&
|
||||
fsp->fi_cip->clean < max_free_segs * IDLE_LIM) {
|
||||
clean_fs(fsp, cost_benefit, nsegs, options);
|
||||
printf("Cleaner running (system idle) at %s",
|
||||
ctime(&now));
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
#ifdef VERBOSE
|
||||
printf("Cleaner not running at %s", ctime(&now));
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
clean_fs(fsp, cost_func, nsegs, options)
|
||||
FS_INFO *fsp; /* file system information */
|
||||
int (*cost_func) __P((FS_INFO *, SEGUSE *));
|
||||
int nsegs;
|
||||
long options;
|
||||
{
|
||||
struct seglist *segs, *sp;
|
||||
int to_clean, cleaned_bytes;
|
||||
int i;
|
||||
|
||||
if ((segs =
|
||||
malloc(fsp->fi_lfs.lfs_nseg * sizeof(struct seglist))) == NULL) {
|
||||
warnx("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) {
|
||||
/* Check which cleaning algorithm to use. */
|
||||
if (options & CLEAN_BYTES) {
|
||||
cleaned_bytes = 0;
|
||||
to_clean = nsegs <<
|
||||
(fsp->fi_lfs.lfs_segshift + fsp->fi_lfs.lfs_bshift);
|
||||
for (sp = segs; i && cleaned_bytes < to_clean;
|
||||
i--, ++sp) {
|
||||
if (clean_segment(fsp, sp->sl_id) < 0)
|
||||
warn("clean_segment failed");
|
||||
else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,
|
||||
sp->sl_id) < 0)
|
||||
warn("lfs_segclean failed");
|
||||
printf("Cleaned segment %d (%d bytes)\n",
|
||||
sp->sl_id, sp->sl_bytes);
|
||||
cleaned_bytes += sp->sl_bytes;
|
||||
}
|
||||
} else
|
||||
for (i = MIN(i, nsegs), sp = segs; i-- ; ++sp) {
|
||||
if (clean_segment(fsp, sp->sl_id) < 0)
|
||||
warn("clean_segment failed");
|
||||
else if (lfs_segclean(&fsp->fi_statfsp->f_fsid,
|
||||
sp->sl_id) < 0)
|
||||
warn("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.
|
||||
*/
|
||||
int
|
||||
cost_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.
|
||||
*/
|
||||
int
|
||||
choose_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_bytes = sup->su_nbytes;
|
||||
++sp;
|
||||
}
|
||||
nsegs = sp - seglist;
|
||||
qsort(seglist, nsegs, sizeof(struct seglist), cost_compare);
|
||||
#ifdef VERBOSE
|
||||
(void)printf("Returning %d segments\n", nsegs);
|
||||
#endif
|
||||
return (nsegs);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
clean_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;
|
||||
double util;
|
||||
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) {
|
||||
warn("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) {
|
||||
warn("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) {
|
||||
warn("clean_segment: lfs_bmapv failed");
|
||||
++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.segs_cleaned;
|
||||
cleaner_stats.blocks_written += num_blocks;
|
||||
util = ((double)num_blocks / fsp->fi_lfs.lfs_ssize);
|
||||
cleaner_stats.util_tot += util;
|
||||
cleaner_stats.util_sos += util * util;
|
||||
|
||||
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) {
|
||||
warn("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);
|
||||
if (stat_report && cleaner_stats.segs_cleaned % stat_report == 0)
|
||||
sig_report(SIGUSR1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
bi_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);
|
||||
}
|
||||
|
||||
void
|
||||
sig_report(sig)
|
||||
int sig;
|
||||
{
|
||||
double avg;
|
||||
|
||||
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);
|
||||
printf("\t\t%s%5.2f\n\t\t%s%5.2f\n",
|
||||
"util_tot ", cleaner_stats.util_tot,
|
||||
"util_sos ", cleaner_stats.util_sos);
|
||||
printf("\t\tavg util: %4.2f std dev: %9.6f\n",
|
||||
avg = cleaner_stats.util_tot / cleaner_stats.segs_cleaned,
|
||||
cleaner_stats.util_sos / cleaner_stats.segs_cleaned - avg * avg);
|
||||
|
||||
|
||||
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;
|
||||
cleaner_stats.util_tot = 0.0;
|
||||
cleaner_stats.util_sos = 0.0;
|
||||
}
|
||||
if (sig == SIGINT)
|
||||
exit(0);
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
.\" Copyright (c) 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.
|
||||
.\"
|
||||
.\" @(#)lfs_cleanerd.8 8.2 (Berkeley) 12/11/93
|
||||
.\" $Id: lfs_cleanerd.8,v 1.6 1997/06/23 04:02:09 steve Exp $
|
||||
.\"
|
||||
.Dd December 11, 1993
|
||||
.Dt LFS_CLEANERD 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm lfs_cleanerd
|
||||
.Nd garbage collect a log-structured file system
|
||||
.Sh SYNOPSIS
|
||||
.Nm lfs_cleanerd
|
||||
.Op Fl ds
|
||||
.Pa node
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
command starts a daemon process which garbage-collects
|
||||
the log-structured file system residing at the point named by
|
||||
.Ar node
|
||||
in the global file system namespace.
|
||||
This command is normally executed by
|
||||
.Xr mount_lfs 8
|
||||
when the log-structured file system is mounted.
|
||||
The daemon will exit within a few minutes
|
||||
of when the file system it was cleaning is unmounted.
|
||||
.Pp
|
||||
Garbage collection on a log-structured file system is done by scanning
|
||||
the file system's segments for active, i.e. referenced, data and copying
|
||||
it to new segments.
|
||||
When all of the active data in a given segment has been copied to a new
|
||||
segment that segment can be marked as empty, thus reclaiming the space
|
||||
taken by the inactive data which was in it.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width indent
|
||||
.It Fl d
|
||||
Run in debug mode.
|
||||
Do not become a daemon process, and print debugging information.
|
||||
.It Fl s
|
||||
When cleaning the file system, read data in small chunks.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mount_lfs 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility first appeared in
|
||||
.Bx 4.4 .
|
@ -1,699 +0,0 @@
|
||||
/*-
|
||||
* 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 lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)library.c 8.3 (Berkeley) 5/24/95";
|
||||
#endif
|
||||
static const char rcsid[] =
|
||||
"$Id: library.c,v 1.9 1997/11/24 07:27:02 charnier Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/lfs/lfs.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "clean.h"
|
||||
|
||||
void add_blocks __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
|
||||
daddr_t, daddr_t));
|
||||
void add_inodes __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
|
||||
daddr_t));
|
||||
int bi_compare __P((const void *, const void *));
|
||||
int bi_toss __P((const void *, const void *, const void *));
|
||||
u_long cksum __P((void *, size_t));
|
||||
void get_ifile __P((FS_INFO *, int));
|
||||
int get_superblock __P((FS_INFO *, struct lfs *));
|
||||
int pseg_valid __P((FS_INFO *, SEGSUM *));
|
||||
|
||||
/*
|
||||
* This function will get information on a a filesystem which matches
|
||||
* the name and type given. If a "name" is in a filesystem of the given
|
||||
* type, then buf is filled with that filesystem's info, and the
|
||||
* a non-zero value is returned.
|
||||
*/
|
||||
int
|
||||
fs_getmntinfo(buf, name, type)
|
||||
struct statfs **buf;
|
||||
char *name;
|
||||
char *type;
|
||||
{
|
||||
/* allocate space for the filesystem info */
|
||||
*buf = (struct statfs *)malloc(sizeof(struct statfs));
|
||||
if (*buf == NULL)
|
||||
return 0;
|
||||
|
||||
/* grab the filesystem info */
|
||||
if (statfs(name, *buf) < 0) {
|
||||
free(*buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check to see if it's the one we want */
|
||||
if (strcmp((*buf)->f_fstypename, type) ||
|
||||
strncmp(name, (*buf)->f_mntonname, MNAMELEN)) {
|
||||
/* "this is not the filesystem you're looking for" */
|
||||
free(*buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get all the information available on an LFS file system.
|
||||
* Returns an pointer to an FS_INFO structure, NULL on error.
|
||||
*/
|
||||
FS_INFO *
|
||||
get_fs_info (lstatfsp, use_mmap)
|
||||
struct statfs *lstatfsp; /* IN: pointer to statfs struct */
|
||||
int use_mmap; /* IN: mmap or read */
|
||||
{
|
||||
FS_INFO *fsp;
|
||||
|
||||
fsp = (FS_INFO *)malloc(sizeof(FS_INFO));
|
||||
if (fsp == NULL)
|
||||
return NULL;
|
||||
bzero(fsp, sizeof(FS_INFO));
|
||||
|
||||
fsp->fi_statfsp = lstatfsp;
|
||||
if (get_superblock (fsp, &fsp->fi_lfs))
|
||||
errx(1, "get_fs_info: get_superblock failed");
|
||||
fsp->fi_daddr_shift =
|
||||
fsp->fi_lfs.lfs_bshift - fsp->fi_lfs.lfs_fsbtodb;
|
||||
get_ifile (fsp, use_mmap);
|
||||
return (fsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are reading the ifile then we need to refresh it. Even if
|
||||
* we are mmapping it, it might have grown. Finally, we need to
|
||||
* refresh the file system information (statfs) info.
|
||||
*/
|
||||
void
|
||||
reread_fs_info(fsp, use_mmap)
|
||||
FS_INFO *fsp; /* IN: prointer fs_infos to reread */
|
||||
int use_mmap;
|
||||
{
|
||||
if (statfs(fsp->fi_statfsp->f_mntonname, fsp->fi_statfsp))
|
||||
errx(1, "reread_fs_info: statfs failed");
|
||||
get_ifile (fsp, use_mmap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the superblock from disk (possibly in face of errors)
|
||||
*/
|
||||
int
|
||||
get_superblock (fsp, sbp)
|
||||
FS_INFO *fsp; /* local file system info structure */
|
||||
struct lfs *sbp;
|
||||
{
|
||||
char mntfromname[MNAMELEN+1];
|
||||
int fid;
|
||||
|
||||
strcpy(mntfromname, "/dev/r");
|
||||
strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
|
||||
|
||||
if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
|
||||
warn("get_superblock: bad open");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
get(fid, LFS_LABELPAD, sbp, sizeof(struct lfs));
|
||||
close (fid);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will map the ifile into memory. It causes a
|
||||
* fatal error on failure.
|
||||
*/
|
||||
void
|
||||
get_ifile (fsp, use_mmap)
|
||||
FS_INFO *fsp;
|
||||
int use_mmap;
|
||||
|
||||
{
|
||||
struct stat file_stat;
|
||||
caddr_t ifp;
|
||||
char *ifile_name;
|
||||
int count, fid;
|
||||
|
||||
ifp = NULL;
|
||||
ifile_name = malloc(strlen(fsp->fi_statfsp->f_mntonname) +
|
||||
strlen(IFILE_NAME)+2);
|
||||
strcat(strcat(strcpy(ifile_name, fsp->fi_statfsp->f_mntonname), "/"),
|
||||
IFILE_NAME);
|
||||
|
||||
if ((fid = open(ifile_name, O_RDWR, (mode_t)0)) < 0)
|
||||
err(1, "get_ifile: bad open");
|
||||
|
||||
if (fstat (fid, &file_stat))
|
||||
err(1, "get_ifile: fstat failed");
|
||||
|
||||
if (use_mmap && file_stat.st_size == fsp->fi_ifile_length) {
|
||||
(void) close(fid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the ifile */
|
||||
if (use_mmap) {
|
||||
if (fsp->fi_cip)
|
||||
munmap((caddr_t)fsp->fi_cip, fsp->fi_ifile_length);
|
||||
ifp = mmap ((caddr_t)0, file_stat.st_size,
|
||||
PROT_READ|PROT_WRITE, MAP_SHARED, fid, (off_t)0);
|
||||
if (ifp == MAP_FAILED)
|
||||
err(1, "get_ifile: mmap failed");
|
||||
} else {
|
||||
if (fsp->fi_cip)
|
||||
free(fsp->fi_cip);
|
||||
if (!(ifp = malloc (file_stat.st_size)))
|
||||
errx(1, "get_ifile: malloc failed");
|
||||
redo_read:
|
||||
count = read (fid, ifp, (size_t) file_stat.st_size);
|
||||
|
||||
if (count < 0)
|
||||
err(1, "get_ifile: bad ifile read");
|
||||
else if (count < file_stat.st_size) {
|
||||
warnx("get_ifile");
|
||||
if (lseek(fid, 0, SEEK_SET) < 0)
|
||||
err(1, "get_ifile: bad ifile lseek");
|
||||
goto redo_read;
|
||||
}
|
||||
}
|
||||
fsp->fi_ifile_length = file_stat.st_size;
|
||||
close (fid);
|
||||
|
||||
fsp->fi_cip = (CLEANERINFO *)ifp;
|
||||
fsp->fi_segusep = (SEGUSE *)(ifp + CLEANSIZE(fsp));
|
||||
fsp->fi_ifilep = (IFILE *)((caddr_t)fsp->fi_segusep + SEGTABSIZE(fsp));
|
||||
|
||||
/*
|
||||
* The number of ifile entries is equal to the number of blocks
|
||||
* blocks in the ifile minus the ones allocated to cleaner info
|
||||
* and segment usage table multiplied by the number of ifile
|
||||
* entries per page.
|
||||
*/
|
||||
fsp->fi_ifile_count = (fsp->fi_ifile_length >> fsp->fi_lfs.lfs_bshift -
|
||||
fsp->fi_lfs.lfs_cleansz - fsp->fi_lfs.lfs_segtabsz) *
|
||||
fsp->fi_lfs.lfs_ifpb;
|
||||
|
||||
free (ifile_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will scan a segment and return a list of
|
||||
* <inode, blocknum> pairs which indicate which blocks were
|
||||
* contained as live data within the segment when the segment
|
||||
* summary was read (it may have "died" since then). Any given
|
||||
* pair will be listed at most once.
|
||||
*/
|
||||
int
|
||||
lfs_segmapv(fsp, seg, seg_buf, blocks, bcount)
|
||||
FS_INFO *fsp; /* pointer to local file system information */
|
||||
int seg; /* the segment number */
|
||||
caddr_t seg_buf; /* the buffer containing the segment's data */
|
||||
BLOCK_INFO **blocks; /* OUT: array of block_info for live blocks */
|
||||
int *bcount; /* OUT: number of active blocks in segment */
|
||||
{
|
||||
BLOCK_INFO *bip;
|
||||
SEGSUM *sp;
|
||||
SEGUSE *sup;
|
||||
struct lfs *lfsp;
|
||||
caddr_t s, segend;
|
||||
daddr_t pseg_addr, seg_addr;
|
||||
int nelem, nblocks, nsegs;
|
||||
#ifdef DIAGNOSTIC
|
||||
FINFO *fip;
|
||||
int i, sumsize;
|
||||
#endif /* DIAGNOSTIC */
|
||||
time_t timestamp;
|
||||
|
||||
lfsp = &fsp->fi_lfs;
|
||||
nelem = 2 * lfsp->lfs_ssize;
|
||||
if (!(bip = malloc(nelem * sizeof(BLOCK_INFO))))
|
||||
goto err0;
|
||||
|
||||
sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, seg);
|
||||
s = seg_buf + (sup->su_flags & SEGUSE_SUPERBLOCK ? LFS_SBPAD : 0);
|
||||
seg_addr = sntoda(lfsp, seg);
|
||||
pseg_addr = seg_addr +
|
||||
(sup->su_flags & SEGUSE_SUPERBLOCK ? btodb(LFS_SBPAD) : 0);
|
||||
#ifdef VERBOSE
|
||||
printf("\tsegment buffer at: 0x%x\tseg_addr 0x%x\n", s, seg_addr);
|
||||
#endif /* VERBOSE */
|
||||
|
||||
*bcount = 0;
|
||||
for (nsegs = 0, timestamp = 0; nsegs < sup->su_nsums; nsegs++) {
|
||||
sp = (SEGSUM *)s;
|
||||
|
||||
nblocks = pseg_valid(fsp, sp);
|
||||
if (nblocks <= 0) {
|
||||
printf("Warning: invalid segment summary at 0x%x\n",
|
||||
pseg_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE
|
||||
printf("\tpartial at: 0x%x\n", pseg_addr);
|
||||
print_SEGSUM(lfsp, sp);
|
||||
fflush(stdout);
|
||||
#endif /* VERBOSE */
|
||||
|
||||
/* Check if we have hit old data */
|
||||
if (timestamp > ((SEGSUM*)s)->ss_create)
|
||||
break;
|
||||
timestamp = ((SEGSUM*)s)->ss_create;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/* Verify size of summary block */
|
||||
sumsize = sizeof(SEGSUM) +
|
||||
(sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
|
||||
for (i = 0, fip = (FINFO *)(sp + 1); i < sp->ss_nfinfo; ++i) {
|
||||
sumsize += sizeof(FINFO) +
|
||||
(fip->fi_nblocks - 1) * sizeof(daddr_t);
|
||||
fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks]);
|
||||
}
|
||||
if (sumsize > LFS_SUMMARY_SIZE)
|
||||
errx(1, "segment %d summary block too big: %d",
|
||||
seg, sumsize);
|
||||
#endif
|
||||
|
||||
if (*bcount + nblocks + sp->ss_ninos > nelem) {
|
||||
nelem = *bcount + nblocks + sp->ss_ninos;
|
||||
bip = realloc (bip, nelem * sizeof(BLOCK_INFO));
|
||||
if (!bip)
|
||||
goto err0;
|
||||
}
|
||||
add_blocks(fsp, bip, bcount, sp, seg_buf, seg_addr, pseg_addr);
|
||||
add_inodes(fsp, bip, bcount, sp, seg_buf, seg_addr);
|
||||
pseg_addr += fsbtodb(lfsp, nblocks) +
|
||||
bytetoda(fsp, LFS_SUMMARY_SIZE);
|
||||
s += (nblocks << lfsp->lfs_bshift) + LFS_SUMMARY_SIZE;
|
||||
}
|
||||
qsort(bip, *bcount, sizeof(BLOCK_INFO), bi_compare);
|
||||
toss(bip, bcount, sizeof(BLOCK_INFO), bi_toss, NULL);
|
||||
#ifdef VERBOSE
|
||||
{
|
||||
BLOCK_INFO *_bip;
|
||||
int i;
|
||||
|
||||
printf("BLOCK INFOS\n");
|
||||
for (_bip = bip, i=0; i < *bcount; ++_bip, ++i)
|
||||
PRINT_BINFO(_bip);
|
||||
}
|
||||
#endif
|
||||
*blocks = bip;
|
||||
return (0);
|
||||
|
||||
err0: *bcount = 0;
|
||||
return (-1);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* This will parse a partial segment and fill in BLOCK_INFO structures
|
||||
* for each block described in the segment summary. It will not include
|
||||
* blocks or inodes from files with new version numbers.
|
||||
*/
|
||||
void
|
||||
add_blocks (fsp, bip, countp, sp, seg_buf, segaddr, psegaddr)
|
||||
FS_INFO *fsp; /* pointer to super block */
|
||||
BLOCK_INFO *bip; /* Block info array */
|
||||
int *countp; /* IN/OUT: number of blocks in array */
|
||||
SEGSUM *sp; /* segment summmary pointer */
|
||||
caddr_t seg_buf; /* buffer containing segment */
|
||||
daddr_t segaddr; /* address of this segment */
|
||||
daddr_t psegaddr; /* address of this partial segment */
|
||||
{
|
||||
IFILE *ifp;
|
||||
FINFO *fip;
|
||||
caddr_t bp;
|
||||
daddr_t *dp, *iaddrp;
|
||||
int db_per_block, i, j;
|
||||
int db_frag;
|
||||
u_long page_size;
|
||||
long *lp;
|
||||
|
||||
#ifdef VERBOSE
|
||||
printf("FILE INFOS\n");
|
||||
#endif
|
||||
db_per_block = fsbtodb(&fsp->fi_lfs, 1);
|
||||
page_size = fsp->fi_lfs.lfs_bsize;
|
||||
bp = seg_buf + datobyte(fsp, psegaddr - segaddr) + LFS_SUMMARY_SIZE;
|
||||
bip += *countp;
|
||||
psegaddr += bytetoda(fsp, LFS_SUMMARY_SIZE);
|
||||
iaddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
|
||||
--iaddrp;
|
||||
for (fip = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo;
|
||||
++i, fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks])) {
|
||||
|
||||
ifp = IFILE_ENTRY(&fsp->fi_lfs, fsp->fi_ifilep, fip->fi_ino);
|
||||
PRINT_FINFO(fip, ifp);
|
||||
if (ifp->if_version > fip->fi_version)
|
||||
continue;
|
||||
dp = &(fip->fi_blocks[0]);
|
||||
for (j = 0; j < fip->fi_nblocks; j++, dp++) {
|
||||
while (psegaddr == *iaddrp) {
|
||||
psegaddr += db_per_block;
|
||||
bp += page_size;
|
||||
--iaddrp;
|
||||
}
|
||||
bip->bi_inode = fip->fi_ino;
|
||||
bip->bi_lbn = *dp;
|
||||
bip->bi_daddr = psegaddr;
|
||||
bip->bi_segcreate = (time_t)(sp->ss_create);
|
||||
bip->bi_bp = bp;
|
||||
bip->bi_version = ifp->if_version;
|
||||
if (fip->fi_lastlength == page_size) {
|
||||
bip->bi_size = page_size;
|
||||
psegaddr += db_per_block;
|
||||
bp += page_size;
|
||||
} else {
|
||||
db_frag = fragstodb(&(fsp->fi_lfs),
|
||||
numfrags(&(fsp->fi_lfs),
|
||||
fip->fi_lastlength));
|
||||
#ifdef VERBOSE
|
||||
printf("lastlength, frags: %d, %d, %d\n",
|
||||
fip->fi_lastlength, temp,
|
||||
bytetoda(fsp, temp));
|
||||
fflush(stdout);
|
||||
#endif
|
||||
bip->bi_size = fip->fi_lastlength;
|
||||
bp += fip->fi_lastlength;
|
||||
psegaddr += db_frag;
|
||||
}
|
||||
++bip;
|
||||
++(*countp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For a particular segment summary, reads the inode blocks and adds
|
||||
* INODE_INFO structures to the array. Returns the number of inodes
|
||||
* actually added.
|
||||
*/
|
||||
void
|
||||
add_inodes (fsp, bip, countp, sp, seg_buf, seg_addr)
|
||||
FS_INFO *fsp; /* pointer to super block */
|
||||
BLOCK_INFO *bip; /* block info array */
|
||||
int *countp; /* pointer to current number of inodes */
|
||||
SEGSUM *sp; /* segsum pointer */
|
||||
caddr_t seg_buf; /* the buffer containing the segment's data */
|
||||
daddr_t seg_addr; /* disk address of seg_buf */
|
||||
{
|
||||
struct dinode *di = NULL;
|
||||
struct lfs *lfsp;
|
||||
IFILE *ifp;
|
||||
BLOCK_INFO *bp;
|
||||
daddr_t *daddrp;
|
||||
ino_t inum;
|
||||
int i;
|
||||
|
||||
if (sp->ss_ninos <= 0)
|
||||
return;
|
||||
|
||||
bp = bip + *countp;
|
||||
lfsp = &fsp->fi_lfs;
|
||||
#ifdef VERBOSE
|
||||
(void) printf("INODES:\n");
|
||||
#endif
|
||||
daddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
|
||||
for (i = 0; i < sp->ss_ninos; ++i) {
|
||||
if (i % INOPB(lfsp) == 0) {
|
||||
--daddrp;
|
||||
di = (struct dinode *)(seg_buf +
|
||||
((*daddrp - seg_addr) << fsp->fi_daddr_shift));
|
||||
} else
|
||||
++di;
|
||||
|
||||
inum = di->di_inumber;
|
||||
bp->bi_lbn = LFS_UNUSED_LBN;
|
||||
bp->bi_inode = inum;
|
||||
bp->bi_daddr = *daddrp;
|
||||
bp->bi_bp = di;
|
||||
bp->bi_segcreate = sp->ss_create;
|
||||
|
||||
if (inum == LFS_IFILE_INUM) {
|
||||
bp->bi_version = 1; /* Ifile version should be 1 */
|
||||
bp++;
|
||||
++(*countp);
|
||||
PRINT_INODE(1, bp);
|
||||
} else {
|
||||
ifp = IFILE_ENTRY(lfsp, fsp->fi_ifilep, inum);
|
||||
PRINT_INODE(ifp->if_daddr == *daddrp, bp);
|
||||
bp->bi_version = ifp->if_version;
|
||||
if (ifp->if_daddr == *daddrp) {
|
||||
bp++;
|
||||
++(*countp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks the summary checksum and the data checksum to determine if the
|
||||
* segment is valid or not. Returns the size of the partial segment if it
|
||||
* is valid, * and 0 otherwise. Use dump_summary to figure out size of the
|
||||
* the partial as well as whether or not the checksum is valid.
|
||||
*/
|
||||
int
|
||||
pseg_valid (fsp, ssp)
|
||||
FS_INFO *fsp; /* pointer to file system info */
|
||||
SEGSUM *ssp; /* pointer to segment summary block */
|
||||
{
|
||||
caddr_t p;
|
||||
int i, nblocks;
|
||||
u_long *datap;
|
||||
|
||||
if (ssp->ss_magic != SS_MAGIC)
|
||||
return(0);
|
||||
|
||||
if ((nblocks = dump_summary(&fsp->fi_lfs, ssp, 0, NULL)) <= 0 ||
|
||||
nblocks > fsp->fi_lfs.lfs_ssize - 1)
|
||||
return(0);
|
||||
|
||||
/* check data/inode block(s) checksum too */
|
||||
datap = (u_long *)malloc(nblocks * sizeof(u_long));
|
||||
p = (caddr_t)ssp + LFS_SUMMARY_SIZE;
|
||||
for (i = 0; i < nblocks; ++i) {
|
||||
datap[i] = *((u_long *)p);
|
||||
p += fsp->fi_lfs.lfs_bsize;
|
||||
}
|
||||
if (cksum ((void *)datap, nblocks * sizeof(u_long)) != ssp->ss_datasum)
|
||||
return (0);
|
||||
|
||||
return (nblocks);
|
||||
}
|
||||
|
||||
|
||||
/* #define MMAP_SEGMENT */
|
||||
/*
|
||||
* read a segment into a memory buffer
|
||||
*/
|
||||
int
|
||||
mmap_segment (fsp, segment, segbuf, use_mmap)
|
||||
FS_INFO *fsp; /* file system information */
|
||||
int segment; /* segment number */
|
||||
caddr_t *segbuf; /* pointer to buffer area */
|
||||
int use_mmap; /* mmap instead of read */
|
||||
{
|
||||
struct lfs *lfsp;
|
||||
int fid; /* fildes for file system device */
|
||||
daddr_t seg_daddr; /* base disk address of segment */
|
||||
off_t seg_byte;
|
||||
size_t ssize;
|
||||
char mntfromname[MNAMELEN+2];
|
||||
|
||||
lfsp = &fsp->fi_lfs;
|
||||
|
||||
/* get the disk address of the beginning of the segment */
|
||||
seg_daddr = sntoda(lfsp, segment);
|
||||
seg_byte = datobyte(fsp, seg_daddr);
|
||||
ssize = seg_size(lfsp);
|
||||
|
||||
strcpy(mntfromname, "/dev/r");
|
||||
strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
|
||||
|
||||
if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
|
||||
warn("mmap_segment: bad open");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (use_mmap) {
|
||||
*segbuf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ,
|
||||
MAP_SHARED, fid, seg_byte);
|
||||
if (*segbuf == MAP_FAILED) {
|
||||
warn("mmap_segment: mmap failed");
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
#ifdef VERBOSE
|
||||
printf("mmap_segment\tseg_daddr: %lu\tseg_size: %lu\tseg_offset: %qu\n",
|
||||
seg_daddr, ssize, seg_byte);
|
||||
#endif
|
||||
/* malloc the space for the buffer */
|
||||
*segbuf = malloc(ssize);
|
||||
if (!*segbuf) {
|
||||
warnx("mmap_segment: malloc failed");
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* read the segment data into the buffer */
|
||||
if (lseek (fid, seg_byte, SEEK_SET) != seg_byte) {
|
||||
warn("mmap_segment: bad lseek");
|
||||
free(*segbuf);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (read (fid, *segbuf, ssize) != ssize) {
|
||||
warn("mmap_segment: bad read");
|
||||
free(*segbuf);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
close (fid);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
munmap_segment (fsp, seg_buf, use_mmap)
|
||||
FS_INFO *fsp; /* file system information */
|
||||
caddr_t seg_buf; /* pointer to buffer area */
|
||||
int use_mmap; /* mmap instead of read/write */
|
||||
{
|
||||
if (use_mmap)
|
||||
munmap (seg_buf, seg_size(&fsp->fi_lfs));
|
||||
else
|
||||
free (seg_buf);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* USEFUL DEBUGGING TOOLS:
|
||||
*/
|
||||
void
|
||||
print_SEGSUM (lfsp, p)
|
||||
struct lfs *lfsp;
|
||||
SEGSUM *p;
|
||||
{
|
||||
if (p)
|
||||
(void) dump_summary(lfsp, p, DUMP_ALL, NULL);
|
||||
else printf("0x0");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int
|
||||
bi_compare(a, b)
|
||||
const void *a;
|
||||
const void *b;
|
||||
{
|
||||
const BLOCK_INFO *ba, *bb;
|
||||
int diff;
|
||||
|
||||
ba = a;
|
||||
bb = b;
|
||||
|
||||
if ((diff = (int)(ba->bi_inode - bb->bi_inode)))
|
||||
return (diff);
|
||||
if ((diff = (int)(ba->bi_lbn - bb->bi_lbn))) {
|
||||
if (ba->bi_lbn == LFS_UNUSED_LBN)
|
||||
return(-1);
|
||||
else if (bb->bi_lbn == LFS_UNUSED_LBN)
|
||||
return(1);
|
||||
else if (ba->bi_lbn < 0 && bb->bi_lbn >= 0)
|
||||
return(1);
|
||||
else if (bb->bi_lbn < 0 && ba->bi_lbn >= 0)
|
||||
return(-1);
|
||||
else
|
||||
return (diff);
|
||||
}
|
||||
if ((diff = (int)(ba->bi_segcreate - bb->bi_segcreate)))
|
||||
return (diff);
|
||||
diff = (int)(ba->bi_daddr - bb->bi_daddr);
|
||||
return (diff);
|
||||
}
|
||||
|
||||
int
|
||||
bi_toss(dummy, a, b)
|
||||
const void *dummy;
|
||||
const void *a;
|
||||
const void *b;
|
||||
{
|
||||
const BLOCK_INFO *ba, *bb;
|
||||
|
||||
ba = a;
|
||||
bb = b;
|
||||
|
||||
return(ba->bi_inode == bb->bi_inode && ba->bi_lbn == bb->bi_lbn);
|
||||
}
|
||||
|
||||
void
|
||||
toss(p, nump, size, dotoss, client)
|
||||
void *p;
|
||||
int *nump;
|
||||
size_t size;
|
||||
int (*dotoss) __P((const void *, const void *, const void *));
|
||||
void *client;
|
||||
{
|
||||
int i;
|
||||
void *p1;
|
||||
|
||||
if (*nump == 0)
|
||||
return;
|
||||
|
||||
for (i = *nump; --i > 0;) {
|
||||
p1 = p + size;
|
||||
if (dotoss(client, p, p1)) {
|
||||
memmove(p, p1, i * size);
|
||||
--(*nump);
|
||||
} else
|
||||
p += size;
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*-
|
||||
* 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 lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif
|
||||
static const char rcsid[] =
|
||||
"$Id$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void
|
||||
get(fd, off, p, len)
|
||||
int fd;
|
||||
off_t off;
|
||||
void *p;
|
||||
size_t len;
|
||||
{
|
||||
int rbytes;
|
||||
|
||||
if (lseek(fd, off, SEEK_SET) < 0)
|
||||
err(1, NULL);
|
||||
if ((rbytes = read(fd, p, len)) < 0)
|
||||
err(1, NULL);
|
||||
if (rbytes != len)
|
||||
errx(1, "short read (%d, not %d)", rbytes, len);
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
/*-
|
||||
* 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 lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif
|
||||
static const char rcsid[] =
|
||||
"$Id$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/lfs/lfs.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "clean.h"
|
||||
|
||||
u_long cksum __P((void *, size_t));
|
||||
|
||||
/*
|
||||
* Print out a summary block; return number of blocks in segment; 0
|
||||
* for empty segment or corrupt segment.
|
||||
* Returns a pointer to the array of inode addresses.
|
||||
*/
|
||||
int
|
||||
dump_summary(lfsp, sp, flags, iaddrp)
|
||||
struct lfs *lfsp;
|
||||
SEGSUM *sp;
|
||||
u_long flags;
|
||||
daddr_t **iaddrp;
|
||||
{
|
||||
int i, j, numblocks;
|
||||
daddr_t *dp;
|
||||
|
||||
FINFO *fp;
|
||||
int ck;
|
||||
|
||||
if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum,
|
||||
LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum))))
|
||||
return(-1);
|
||||
|
||||
if (flags & DUMP_SUM_HEADER) {
|
||||
(void)printf(" %s0x%X\t%s%d\t%s%d\n %s0x%X\t%s0x%X",
|
||||
"next ", sp->ss_next,
|
||||
"nfinfo ", sp->ss_nfinfo,
|
||||
"ninos ", sp->ss_ninos,
|
||||
"sumsum ", sp->ss_sumsum,
|
||||
"datasum ", sp->ss_datasum );
|
||||
(void)printf("\tcreate %s", ctime((time_t *)&sp->ss_create));
|
||||
}
|
||||
|
||||
numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
|
||||
|
||||
/* Dump out inode disk addresses */
|
||||
if (flags & DUMP_INODE_ADDRS)
|
||||
printf(" Inode addresses:");
|
||||
|
||||
dp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
|
||||
for (--dp, i = 0; i < sp->ss_ninos; --dp)
|
||||
if (flags & DUMP_INODE_ADDRS) {
|
||||
(void)printf("\t0x%lx", *dp);
|
||||
if (++i % 7 == 0)
|
||||
(void)printf("\n");
|
||||
} else
|
||||
++i;
|
||||
if (iaddrp)
|
||||
*iaddrp = ++dp;
|
||||
if (flags & DUMP_INODE_ADDRS)
|
||||
printf("\n");
|
||||
|
||||
for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; ++i) {
|
||||
numblocks += fp->fi_nblocks;
|
||||
if (flags & DUMP_FINFOS) {
|
||||
(void)printf(" %s%d version %d nblocks %d\n",
|
||||
"FINFO for inode: ", fp->fi_ino,
|
||||
fp->fi_version, fp->fi_nblocks);
|
||||
dp = &(fp->fi_blocks[0]);
|
||||
for (j = 0; j < fp->fi_nblocks; j++, dp++) {
|
||||
(void)printf("\t%d", *dp);
|
||||
if ((j % 8) == 7)
|
||||
(void)printf("\n");
|
||||
}
|
||||
if ((j % 8) != 0)
|
||||
(void)printf("\n");
|
||||
fp = (FINFO *)dp;
|
||||
} else {
|
||||
fp = (FINFO *)(&fp->fi_blocks[fp->fi_nblocks]);
|
||||
}
|
||||
}
|
||||
return (numblocks);
|
||||
}
|
||||
|
||||
#ifdef VERBOSE
|
||||
void
|
||||
dump_cleaner_info(ipage)
|
||||
void *ipage;
|
||||
{
|
||||
CLEANERINFO *cip;
|
||||
|
||||
cip = (CLEANERINFO *)ipage;
|
||||
(void)printf("segments clean\t%d\tsegments dirty\t%d\n\n",
|
||||
cip->clean, cip->dirty);
|
||||
}
|
||||
|
||||
void
|
||||
dump_super(lfsp)
|
||||
struct lfs *lfsp;
|
||||
{
|
||||
int i;
|
||||
|
||||
(void)printf("%s0x%X\t%s0x%X\t%s%d\t%s%d\n",
|
||||
"magic ", lfsp->lfs_magic,
|
||||
"version ", lfsp->lfs_version,
|
||||
"size ", lfsp->lfs_size,
|
||||
"ssize ", lfsp->lfs_ssize);
|
||||
(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
|
||||
"dsize ", lfsp->lfs_dsize,
|
||||
"bsize ", lfsp->lfs_bsize,
|
||||
"fsize ", lfsp->lfs_fsize,
|
||||
"frag ", lfsp->lfs_frag);
|
||||
|
||||
(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
|
||||
"minfree ", lfsp->lfs_minfree,
|
||||
"inopb ", lfsp->lfs_inopb,
|
||||
"ifpb ", lfsp->lfs_ifpb,
|
||||
"nindir ", lfsp->lfs_nindir);
|
||||
|
||||
(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
|
||||
"nseg ", lfsp->lfs_nseg,
|
||||
"nspf ", lfsp->lfs_nspf,
|
||||
"cleansz ", lfsp->lfs_cleansz,
|
||||
"segtabsz ", lfsp->lfs_segtabsz);
|
||||
|
||||
(void)printf("%s0x%X\t%s%d\t%s0x%X\t%s%d\n",
|
||||
"segmask ", lfsp->lfs_segmask,
|
||||
"segshift ", lfsp->lfs_segshift,
|
||||
"bmask ", lfsp->lfs_bmask,
|
||||
"bshift ", lfsp->lfs_bshift);
|
||||
|
||||
(void)printf("%s0x%X\t\t%s%d\t%s0x%X\t%s%d\n",
|
||||
"ffmask ", lfsp->lfs_ffmask,
|
||||
"ffshift ", lfsp->lfs_ffshift,
|
||||
"fbmask ", lfsp->lfs_fbmask,
|
||||
"fbshift ", lfsp->lfs_fbshift);
|
||||
|
||||
(void)printf("%s%d\t\t%s0x%X\t%s0x%qx\n",
|
||||
"fsbtodb ", lfsp->lfs_fsbtodb,
|
||||
"cksum ", lfsp->lfs_cksum,
|
||||
"maxfilesize ", lfsp->lfs_maxfilesize);
|
||||
|
||||
(void)printf("Superblock disk addresses:\t");
|
||||
for (i = 0; i < LFS_MAXNUMSB; i++) {
|
||||
(void)printf(" 0x%X", lfsp->lfs_sboffs[i]);
|
||||
if ( i == (LFS_MAXNUMSB >> 1))
|
||||
(void)printf("\n\t\t\t\t");
|
||||
}
|
||||
(void)printf("\n");
|
||||
|
||||
(void)printf("Checkpoint Info\n");
|
||||
(void)printf("%s%d\t%s0x%X\t%s%d\n",
|
||||
"free ", lfsp->lfs_free,
|
||||
"idaddr ", lfsp->lfs_idaddr,
|
||||
"ifile ", lfsp->lfs_ifile);
|
||||
(void)printf("%s%d\t%s%d\t%s%d\n",
|
||||
"bfree ", lfsp->lfs_bfree,
|
||||
"avail ", lfsp->lfs_avail,
|
||||
"uinodes ", lfsp->lfs_uinodes);
|
||||
(void)printf("%s%d\t%s0x%X\t%s0x%X\n%s0x%X\t%s0x%X\t",
|
||||
"nfiles ", lfsp->lfs_nfiles,
|
||||
"lastseg ", lfsp->lfs_lastseg,
|
||||
"nextseg ", lfsp->lfs_nextseg,
|
||||
"curseg ", lfsp->lfs_curseg,
|
||||
"offset ", lfsp->lfs_offset);
|
||||
(void)printf("tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp));
|
||||
(void)printf("\nIn-Memory Information\n");
|
||||
(void)printf("%s%d\t%s0x%X\t%s%d\t%s%d\t%s%d\n",
|
||||
"seglock ", lfsp->lfs_seglock,
|
||||
"iocount ", lfsp->lfs_iocount,
|
||||
"writer ", lfsp->lfs_writer,
|
||||
"dirops ", lfsp->lfs_dirops,
|
||||
"doifile ", lfsp->lfs_doifile );
|
||||
(void)printf("%s%d\t%s%d\t%s0x%X\t%s%d\n",
|
||||
"nactive ", lfsp->lfs_nactive,
|
||||
"fmod ", lfsp->lfs_fmod,
|
||||
"clean ", lfsp->lfs_clean,
|
||||
"ronly ", lfsp->lfs_ronly);
|
||||
}
|
||||
#endif /* VERBOSE */
|
Loading…
Reference in New Issue
Block a user