A new version of the cleaner. In general, works about as well as the old

cleaner, but with more legible code.

Includes code for reading and writing to the raw disk device (so that an
unmounted fs could be cleaned), for the use of a single daemon to clean
multiple filesystems to save on resources, and for recording the old
contents of cleaned segments to offline storage for regression testing of
the LFS system as a whole; though these new features are not properly
tested at this point.
This commit is contained in:
perseant 2006-03-30 19:10:13 +00:00
parent 162bcf9406
commit 9c75397609
13 changed files with 2223 additions and 2571 deletions

View File

@ -1,15 +1,20 @@
# $NetBSD: Makefile,v 1.9 2002/08/19 13:54:36 lukem Exp $
# from: @(#)Makefile 8.1 (Berkeley) 6/5/93
# $NetBSD: Makefile,v 1.10 2006/03/30 19:10:13 perseant Exp $
# @(#)Makefile 8.1 (Berkeley) 6/18/93
.include <bsd.own.mk>
PROG= lfs_cleanerd
CPPFLAGS+=-I${.CURDIR} -DDIAGNOSTIC
SRCS= lfs_cleanerd.c fdfs.c coalesce.c cleansrv.c
SRCS+= lfs_cksum.c
SRCS+= bufcache.c vnode.c lfs.c # segwrite.c
MAN= lfs_cleanerd.8
SRCS= cleanerd.c lfs_cksum.c library.c misc.c print.c coalesce.c
LDADD+=-lutil
DPADD+=${LIBUTIL}
.PATH: ${NETBSDSRCDIR}/sys/ufs/lfs ${NETBSDSRCDIR}/sbin/fsck_lfs
.PATH: ${NETBSDSRCDIR}/sys/ufs/lfs
FSCK_LFS= ${NETBSDSRCDIR}/sbin/fsck_lfs
DPADD= ${LIBUTIL}
LDADD= -lutil
CPPFLAGS+=-I${FSCK_LFS} # -DUSE_CLIENT_SERVER
#CPPFLAGS+=-DREPAIR_ZERO_FINFO
#CPPFLAGS+=-DTEST_PATTERN
.include <bsd.prog.mk>

View File

@ -1,175 +0,0 @@
/* $NetBSD: clean.h,v 1.21 2005/08/19 02:06:29 christos Exp $ */
/*-
* 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. 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
*/
/*
* 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) (3)
#define NUM_TO_CLEAN(fsp) (1)
#define MAXLOADS 3
#define ONE_MIN 0
#define FIVE_MIN 1
#define FIFTEEN_MIN 2
#define TIME_THRESHOLD 5 /* Time to tell looping from running */
#define LOOP_THRESHOLD 5 /* Number of looping respawns before exit */
#include <sys/time.h>
typedef struct fs_info {
struct statvfs *fi_statvfsp; /* 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_ifile_count; /* # entries in the ifile table */
off_t fi_ifile_length; /* length of the ifile */
time_t fi_fs_tstamp; /* last fs activity, per 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) fsbtob((fs), segtod((fs), 1))
#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, ife, i) \
((fs)->lfs_version == 1 ? \
(IFILE *)((IFILE_V1 *)((caddr_t)(ife) + ((i) / (fs)->lfs_ifpb <<\
(fs)->lfs_bshift)) + (i) % (fs)->lfs_ifpb) : \
((IFILE *)((caddr_t)(ife) + ((i) / (fs)->lfs_ifpb << \
(fs)->lfs_bshift)) + (i) % (fs)->lfs_ifpb))
#define SEGUSE_ENTRY(fs, su, i) \
((fs)->lfs_version == 1 ? \
(SEGUSE *)((SEGUSE_V1 *)((caddr_t)(su) + (fs)->lfs_bsize * \
((i) / (fs)->lfs_sepb)) + \
(i) % (fs)->lfs_sepb) : \
((SEGUSE *)((caddr_t)(su) + (fs)->lfs_bsize * \
((i) / (fs)->lfs_sepb)) + \
(i) % (fs)->lfs_sepb))
/*
* USEFUL DEBUGGING FUNCTIONS:
*/
#define PRINT_FINFO(fp, ip) if(debug > 1) { \
syslog(LOG_DEBUG," %s %s%u 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); \
}
#define PRINT_INODE(b, bip) if(debug > 1) { \
syslog(LOG_DEBUG,"\t%s inode: %llu daddr: 0x%lx create: %s\n", \
b ? "KEEPING" : "TOSSING", (unsigned long long)(bip)->bi_inode, \
(long)(bip)->bi_daddr, ctime((time_t *)&(bip)->bi_segcreate)); \
}
#define PRINT_BINFO(bip) if(debug > 1 ) { \
syslog(LOG_DEBUG,"\tinode: %llu lbn: %d daddr: 0x%lx create: %s\n", \
(unsigned long long)(bip)->bi_inode, (bip)->bi_lbn, \
(unsigned long)(bip)->bi_daddr, \
ctime((time_t *)&(bip)->bi_segcreate)); \
}
#define PRINT_SEGUSE(sup, n) if(debug > 1) { \
syslog(LOG_DEBUG,"Segment %d nbytes=%lu\tflags=%c%c%c ninos=%d nsums=%d lastmod: %s", \
n, (unsigned long)(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)); \
}
extern int ifile_fd; /* Ifile file descriptor */
__BEGIN_DECLS
/* XXX ondisk32 */
int dump_summary(struct lfs *, SEGSUM *, u_long, int32_t **, daddr_t);
int fs_getmntinfo(struct statvfs **, char *, const char *);
void get(int, off_t, void *, size_t);
struct ufs1_dinode *get_dinode (FS_INFO *, ino_t);
int get_rawblock(FS_INFO *, char *, size_t, daddr_t);
FS_INFO *get_fs_info(struct statvfs *, int);
int lfs_segmapv(FS_INFO *, int, caddr_t, BLOCK_INFO **, int *);
int mmap_segment(FS_INFO *, int, caddr_t *, int);
void munmap_segment(FS_INFO *, caddr_t, int);
void reread_fs_info(FS_INFO *, int);
void toss (void *, int *, size_t,
int (*)(const void *, const void *, const void *), void *);
void log_exit(int, int, char *, ...);
void dump_super(struct lfs *);
void dump_cleaner_info(void *);
void print_SEGSUM(struct lfs *, SEGSUM *, daddr_t);
void print_CLEANERINFO(CLEANERINFO *);
int clean_inode(struct fs_info *, ino_t);
int clean_all_inodes(struct fs_info *);
int fork_coalesce(struct fs_info *);
int lfs_markv_emul(int, BLOCK_INFO *, int);
int lfs_bmapv_emul(int, BLOCK_INFO *, int);
int lfs_segwait_emul(int, struct timeval *);
__END_DECLS

View File

@ -0,0 +1,75 @@
#ifndef CLEANER_H_
#define CLEANER_H_
/*
* An abbreviated version of the SEGUSE data structure.
*/
struct clfs_seguse {
u_int32_t nbytes;
u_int32_t nsums;
u_int32_t flags;
u_int64_t lastmod;
u_int64_t priority;
};
/*
* The cleaner's view of the superblock data structure.
*/
struct clfs {
struct dlfs lfs_dlfs; /* Leverage LFS lfs_* defines here */
/* Ifile */
int clfs_ifilefd; /* Ifile file descriptor */
struct uvnode *lfs_ivnode; /* Ifile vnode */
fhandle_t clfs_ifilefh; /* Ifile file handle */
/* Device */
int clfs_devfd; /* Device file descriptor */
struct uvnode *clfs_devvp; /* Device vnode */
char *clfs_dev; /* Name of device */
/* Cache of segment status */
struct clfs_seguse *clfs_segtab; /* Abbreviated seguse table */
struct clfs_seguse **clfs_segtabp; /* pointers to same */
/* Progress status */
int clfs_nactive; /* How many segments' blocks we have */
int clfs_onhold; /* If cleaning this fs is on hold */
};
/*
* Fraction of the could-be-clean segments required to be clean.
*/
#define BUSY_LIM 0.5
#define IDLE_LIM 0.9
__BEGIN_DECLS
/* lfs_cleanerd.c */
void pwarn(const char *, ...);
void calc_cb(struct clfs *, int, struct clfs_seguse *);
int clean_fs(struct clfs *, CLEANERINFO *);
void dlog(char *, ...);
void handle_error(struct clfs **, int);
int init_fs(struct clfs *, char *);
int invalidate_segment(struct clfs *, int);
void lfs_ientry(IFILE **, struct clfs *, ino_t, struct ubuf **);
int load_segment(struct clfs *, int, BLOCK_INFO **, int *);
int needs_cleaning(struct clfs *, CLEANERINFO *);
int32_t parse_pseg(struct clfs *, daddr_t, BLOCK_INFO **, int *);
int reinit_fs(struct clfs *);
void reload_ifile(struct clfs *);
void toss_old_blocks(struct clfs *, BLOCK_INFO **, int *);
/* cleansrv.c */
void check_control_socket(void);
void try_to_become_master(int, char **);
/* coalesce.c */
int log2int(int);
int clean_all_inodes(struct clfs *);
int fork_coalesce(struct clfs *);
__END_DECLS
#endif /* CLEANER_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,227 @@
/* $NetBSD: cleansrv.c,v 1.1 2006/03/30 19:10:13 perseant Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifdef USE_CLIENT_SERVER
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/syslog.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <ufs/ufs/inode.h>
#include <ufs/lfs/lfs.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "fdfs.h"
#include "cleaner.h"
#define LFS_CLEANERD_SOCKDIR "/tmp/.lfs_cleanerd"
#define LFS_CLEANERD_SOCKFILE LFS_CLEANERD_SOCKDIR "/socket"
int control_socket = -1;
extern int nfss;
extern struct clfs **fsp;
struct lfs_cleanerd_cmd {
int cmd;
int len;
char data[PATH_MAX];
};
void
check_control_socket(void)
{
int c, r;
struct lfs_cleanerd_cmd cmd;
struct clfs **nfsp;
if (control_socket < 0)
return;
while(1) {
ioctl(control_socket, FIONREAD, &c);
if (c <= 0)
return;
read(control_socket, (char *)&cmd, sizeof(cmd));
switch(cmd.cmd) {
case 'C': /* Add filesystem for cleaning */
++nfss;
nfsp = (struct clfs **)realloc(fsp,
nfss * sizeof(*fsp));
if (nfsp == NULL) {
--nfss;
break;
}
fsp = nfsp;
fsp[nfss - 1] = (struct clfs *)malloc(sizeof(**fsp));
if (fsp[nfss - 1] == NULL) {
--nfsp;
break;
}
if ((r = init_fs(fsp[nfss - 1], cmd.data)) < 0) {
syslog(LOG_ERR, "%s: couldn't init: "
"error code %d", cmd.data, r);
handle_error(fsp, nfss - 1);
}
break;
default:
syslog(LOG_NOTICE, "unknown message type %d", cmd.cmd);
break;
}
}
}
static int
send_fss_to_master(int argc, char **argv)
{
struct sockaddr_un sun;
struct lfs_cleanerd_cmd cmd;
int i, r, s;
strcpy(sun.sun_path, LFS_CLEANERD_SOCKFILE);
sun.sun_family = AF_LOCAL;
sun.sun_len = sizeof(sa_family_t) + 1 + strlen(sun.sun_path);
s = socket(PF_LOCAL, SOCK_DGRAM, 0);
if (s < 0) {
syslog(LOG_DEBUG, "open failed: %m");
return -1;
}
cmd.cmd = 'C';
for (i = 0; i < argc; i++) {
strncpy(cmd.data, argv[i], PATH_MAX);
cmd.len = 2 * sizeof(int) + strlen(cmd.data) + 1;
r = sendto(s, &cmd, sizeof(cmd), 0, (struct sockaddr *)&sun,
sizeof(sun));
if (r < 0) {
syslog(LOG_DEBUG, "sendto failed: %m");
return -1;
}
}
return 0;
}
static void
sig_donothing(int sig)
{
/* Do nothing */
dlog("caught sigio");
}
static void
cleanup_socket(void)
{
if (control_socket >= 0) {
close(control_socket);
unlink(LFS_CLEANERD_SOCKFILE);
rmdir(LFS_CLEANERD_SOCKDIR);
}
}
void
try_to_become_master(int argc, char **argv)
{
struct sockaddr_un sun;
int fd;
int pid;
int flags;
char scratch[80];
if (mkdir(LFS_CLEANERD_SOCKDIR, 0700) < 0) {
if (errno != EEXIST)
return;
pid = 0;
fd = open("/var/run/lfs_cleanerd.pid", O_RDONLY);
if (fd >= 0) {
read(fd, scratch, 80);
scratch[79] = '\0';
pid = atoi(scratch);
if (kill(pid, 0) == 0) {
send_fss_to_master(argc, argv);
exit(0);
}
close(fd);
}
/*
* Master is no longer present even though directory
* exists. Remove the socket and proceed. There is
* a race condition here which could result in more than
* one master daemon. That would not be a catastrophe.
*/
if (unlink(LFS_CLEANERD_SOCKFILE) != 0)
return;
}
/*
* Create the socket and bind it in the namespace
*/
control_socket = socket(PF_LOCAL, SOCK_DGRAM, 0);
strcpy(sun.sun_path, LFS_CLEANERD_SOCKFILE);
sun.sun_family = AF_LOCAL;
sun.sun_len = sizeof(sa_family_t) + 1 + strlen(sun.sun_path);
bind(control_socket, (struct sockaddr *)&sun, sizeof(sun));
/* Clean up when we leave */
atexit(cleanup_socket);
/*
* Wake us when there is i/o on this socket. We don't need
* to actually do anything when we get the signal, but we
* have to install a signal handler so LFCNSEGWAIT will be
* interrupted when data comes in on the socket.
*/
fcntl(control_socket, F_SETOWN, getpid());
flags = fcntl(control_socket, F_GETFL, NULL);
flags |= O_ASYNC;
fcntl(control_socket, F_SETFL, flags);
signal(SIGIO, sig_donothing);
/* And finally record our pid */
pidfile("lfs_cleanerd");
}
#endif /* USE_CLIENT_SERVER */

View File

@ -1,7 +1,7 @@
/* $NetBSD: coalesce.c,v 1.10 2005/08/19 02:06:29 christos Exp $ */
/* $NetBSD: coalesce.c,v 1.11 2006/03/30 19:10:13 perseant Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* Copyright (c) 2002, 2005 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -60,25 +60,20 @@
#include <syslog.h>
#include "clean.h"
#include "bufcache.h"
#include "vnode.h"
#include "cleaner.h"
extern int debug, do_mmap;
static int
tossdead(const void *client, const void *a, const void *b)
{
return (((BLOCK_INFO *)a)->bi_daddr <= 0 ||
((BLOCK_INFO *)a)->bi_size == 0);
}
static int log2int(int n)
int log2int(int n)
{
int log;
log = 0;
while (n > 0) {
++log;
n /= 2;
n >>= 1;
}
return log - 1;
}
@ -91,9 +86,9 @@ enum coalesce_returncodes {
COALESCE_BADBLOCKSIZE,
COALESCE_NOMEM,
COALESCE_BADBMAPV,
COALESCE_BADMARKV,
COALESCE_NOTWORTHIT,
COALESCE_NOTHINGLEFT,
COALESCE_NOTHINGLEFT2,
COALESCE_EIO,
COALESCE_MAXERROR
@ -115,30 +110,62 @@ char *coalesce_return[] = {
"No such error"
};
static struct ufs1_dinode *
get_dinode(struct clfs *fs, ino_t ino)
{
IFILE *ifp;
daddr_t daddr;
struct ubuf *bp;
struct ufs1_dinode *dip, *r;
lfs_ientry(&ifp, fs, ino, &bp);
daddr = ifp->if_daddr;
brelse(bp);
if (daddr == 0x0)
return NULL;
bread(fs->clfs_devvp, daddr, fs->lfs_ibsize, NOCRED, &bp);
for (dip = (struct ufs1_dinode *)bp->b_data;
dip < (struct ufs1_dinode *)(bp->b_data + fs->lfs_ibsize); dip++)
if (dip->di_inumber == ino) {
r = (struct ufs1_dinode *)malloc(sizeof(*r));
memcpy(r, dip, sizeof(*r));
brelse(bp);
return r;
}
brelse(bp);
return NULL;
}
/*
* Find out if this inode's data blocks are discontinuous; if they are,
* rewrite them using markv. Return the number of inodes rewritten.
*/
int clean_inode(struct fs_info *fsp, ino_t ino)
static int
clean_inode(struct clfs *fs, ino_t ino)
{
int i, error;
BLOCK_INFO *bip = NULL, *tbip;
CLEANERINFO cip;
struct ubuf *bp;
struct ufs1_dinode *dip;
int nb, onb, noff;
struct clfs_seguse *sup;
struct lfs_fcntl_markv /* {
BLOCK_INFO *blkiov;
int blkcnt;
} */ lim;
daddr_t toff;
struct lfs *lfsp;
int bps;
SEGUSE *sup;
int i;
int nb, onb, noff;
int retval;
int bps;
lfsp = &fsp->fi_lfs;
dip = get_dinode(fsp, ino);
dip = get_dinode(fs, ino);
if (dip == NULL)
return COALESCE_NOINODE;
/* Compute file block size, set up for bmapv */
onb = nb = lblkno(lfsp, dip->di_size);
onb = nb = lblkno(fs, dip->di_size);
/* XXX for now, don't do any file small enough to have fragments */
if (nb < NDADDR)
@ -146,16 +173,12 @@ int clean_inode(struct fs_info *fsp, ino_t ino)
/* Sanity checks */
if (dip->di_size < 0) {
if (debug)
syslog(LOG_DEBUG, "ino %llu, negative size (%lld)",
(unsigned long long)ino, (long long)dip->di_size);
dlog("ino %d, negative size (%" PRId64 ")", ino, dip->di_size);
return COALESCE_BADSIZE;
}
if (nb > dip->di_blocks) {
if (debug)
syslog(LOG_DEBUG, "ino %llu, computed blocks %d "
"> held blocks %d",
(unsigned long long)ino, nb, dip->di_blocks);
dlog("ino %d, computed blocks %d > held blocks %d", ino, nb,
dip->di_blocks);
return COALESCE_BADBLOCKSIZE;
}
@ -172,8 +195,11 @@ int clean_inode(struct fs_info *fsp, ino_t ino)
bip[i].bi_version = dip->di_gen;
/* Don't set the size, but let lfs_bmap fill it in */
}
if ((error = lfs_bmapv_emul(ifile_fd, bip, nb)) < 0) {
syslog(LOG_WARNING, "LFCNBMAPV: %m");
lim.blkiov = bip;
lim.blkcnt = nb;
if (fcntl(fs->clfs_ifilefd, LFCNBMAPV, &lim) < 0) {
syslog(LOG_WARNING, "%s: coalesce: LFCNBMAPV: %m",
fs->lfs_fsmnt);
retval = COALESCE_BADBMAPV;
goto out;
}
@ -187,21 +213,21 @@ int clean_inode(struct fs_info *fsp, ino_t ino)
#endif
noff = toff = 0;
for (i = 1; i < nb; i++) {
if (bip[i].bi_daddr != bip[i - 1].bi_daddr + lfsp->lfs_frag)
if (bip[i].bi_daddr != bip[i - 1].bi_daddr + fs->lfs_frag)
++noff;
toff += abs(bip[i].bi_daddr - bip[i - 1].bi_daddr
- lfsp->lfs_frag) >> lfsp->lfs_fbshift;
- fs->lfs_frag) >> fs->lfs_fbshift;
}
/*
* If this file is not discontinuous, there's no point in rewriting it.
*
* Explicitly allow a certain amount of discontinuity, since large
* files will be broken among segments and medium-sized files
* can have a break or two and it's okay.
*
* Explicitly allow a certain amount of discontinuity, since large
* files will be broken among segments and medium-sized files
* can have a break or two and it's okay.
*/
if (nb <= 1 || noff == 0 || noff < log2int(nb) ||
segtod(lfsp, noff) * 2 < nb) {
segtod(fs, noff) * 2 < nb) {
retval = COALESCE_NOTWORTHIT;
goto out;
} else if (debug)
@ -213,35 +239,32 @@ int clean_inode(struct fs_info *fsp, ino_t ino)
for (i = 0; i < nb; i++) {
if (bip[i].bi_daddr <= 0)
continue;
sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep,
dtosn(lfsp, bip[i].bi_daddr));
if (sup->su_flags & SEGUSE_ACTIVE)
sup = &fs->clfs_segtab[dtosn(fs, bip[i].bi_daddr)];
if (sup->flags & SEGUSE_ACTIVE)
bip[i].bi_daddr = LFS_UNUSED_DADDR; /* 0 */
}
/*
* Get rid of any we've marked dead. If this is an older
* kernel that doesn't have bmapv fill in the block
* sizes, we'll toss everything here.
/*
* Get rid of any blocks we've marked dead. If this is an older
* kernel that doesn't have bmapv fill in the block sizes, we'll
* toss everything here.
*/
toss(bip, &nb, sizeof(BLOCK_INFO), tossdead, NULL);
if (nb && tossdead(NULL, bip + nb - 1, NULL))
--nb;
if (nb == 0) {
retval = COALESCE_NOTHINGLEFT;
goto out;
}
onb = nb;
toss_old_blocks(fs, &bip, &nb);
nb = i;
/*
* We may have tossed enough blocks that it is no longer worthwhile
* to rewrite this inode.
*/
if (onb - nb > log2int(onb)) {
if (nb == 0 || onb - nb > log2int(onb)) {
if (debug)
syslog(LOG_DEBUG, "too many blocks tossed, not rewriting");
return COALESCE_NOTHINGLEFT2;
retval = COALESCE_NOTHINGLEFT;
goto out;
}
/*
/*
* We are going to rewrite this inode.
* For any remaining blocks, read in their contents.
*/
@ -253,8 +276,9 @@ int clean_inode(struct fs_info *fsp, ino_t ino)
retval = COALESCE_NOMEM;
goto out;
}
if (get_rawblock(fsp, bip[i].bi_bp, bip[i].bi_size,
bip[i].bi_daddr) != bip[i].bi_size) {
if (pread(fs->clfs_devfd, bip[i].bi_bp, bip[i].bi_size,
fsbtob(fs, bip[i].bi_daddr)) < 0) {
retval = COALESCE_EIO;
goto out;
}
@ -268,19 +292,29 @@ int clean_inode(struct fs_info *fsp, ino_t ino)
* than half of the available segments, sleep until that's not
* true any more.
*/
bps = segtod(lfsp, 1);
bps = segtod(fs, 1);
for (tbip = bip; tbip < bip + nb; tbip += bps) {
while (fsp->fi_cip->clean < 4) {
lfs_segwait_emul(ifile_fd, NULL);
reread_fs_info(fsp, do_mmap);
/* XXX start over? */
do {
bread(fs->lfs_ivnode, 0, fs->lfs_bsize, NOCRED, &bp);
cip = *(CLEANERINFO *)bp->b_data;
bp->b_flags |= B_INVAL;
brelse(bp);
if (cip.clean < 4) /* XXX magic number 4 */
fcntl(fs->clfs_ifilefd, LFCNSEGWAIT, NULL);
} while(cip.clean < 4);
lim.blkiov = tbip;
lim.blkcnt = (tbip + bps < bip + nb ? bps : nb % bps);
if (fcntl(fs->clfs_ifilefd, LFCNMARKV, &lim) < 0) {
retval = COALESCE_BADMARKV;
goto out;
}
lfs_markv_emul(ifile_fd, tbip,
(tbip + bps < bip + nb ? bps : nb % bps));
}
retval = COALESCE_OK;
out:
free(dip);
if (bip) {
for (i = 0; i < onb; i++)
if (bip[i].bi_bp)
@ -294,34 +328,45 @@ out:
* Try coalescing every inode in the filesystem.
* Return the number of inodes actually altered.
*/
int clean_all_inodes(struct fs_info *fsp)
int clean_all_inodes(struct clfs *fs)
{
int i, r;
int i, r, maxino;
int totals[COALESCE_MAXERROR];
struct stat st;
memset(totals, 0, sizeof(totals));
for (i = 0; i < fsp->fi_ifile_count; i++) {
r = clean_inode(fsp, i);
fstat(fs->clfs_ifilefd, &st);
maxino = fs->lfs_ifpb * (st.st_size >> fs->lfs_bshift) -
fs->lfs_segtabsz - fs->lfs_cleansz;
for (i = 0; i < maxino; i++) {
r = clean_inode(fs, i);
++totals[r];
}
for (i = 0; i < COALESCE_MAXERROR; i++)
if (totals[i])
syslog(LOG_DEBUG, "%s: %d", coalesce_return[i],
totals[i]);
totals[i]);
return totals[COALESCE_OK];
}
int fork_coalesce(struct fs_info *fsp)
/*
* Fork a child process to coalesce this fs.
*/
int
fork_coalesce(struct clfs *fs)
{
static pid_t childpid;
int num;
reread_fs_info(fsp, do_mmap);
/*
* If already running a coalescing child, don't start a new one.
*/
if (childpid) {
if (waitpid(childpid, NULL, WNOHANG) == childpid)
if (waitpid(childpid, NULL, WNOHANG) == childpid)
childpid = 0;
}
if (childpid && kill(childpid, 0) >= 0) {
@ -330,15 +375,22 @@ int fork_coalesce(struct fs_info *fsp)
syslog(LOG_DEBUG, "coalescing already in progress");
return 0;
}
/*
* Fork a child and let the child coalease
*/
childpid = fork();
if (childpid < 0) {
syslog(LOG_ERR, "fork: %m");
syslog(LOG_ERR, "%s: fork to coaleasce: %m", fs->lfs_fsmnt);
return 0;
} else if (childpid == 0) {
syslog(LOG_NOTICE, "new coalescing process, pid %d", getpid());
num = clean_all_inodes(fsp);
syslog(LOG_NOTICE, "coalesced %d discontiguous inodes", num);
syslog(LOG_NOTICE, "%s: new coalescing process, pid %d",
fs->lfs_fsmnt, getpid());
num = clean_all_inodes(fs);
syslog(LOG_NOTICE, "%s: coalesced %d discontiguous inodes",
fs->lfs_fsmnt, num);
exit(0);
}
return 0;
}

283
libexec/lfs_cleanerd/fdfs.c Normal file
View File

@ -0,0 +1,283 @@
/* $NetBSD: fdfs.c,v 1.1 2006/03/30 19:10:13 perseant Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Buffer cache routines for a file-descriptor backed filesystem.
* This is part of lfs_cleanerd so there is also a "segment pointer" that
* we can make buffers out of without duplicating memory or reading the data
* again.
*/
#include <err.h>
#include <fcntl.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syslog.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include "vnode.h"
#include "bufcache.h"
#include "fdfs.h"
/*
* Return a "vnode" interface to a given file descriptor.
*/
struct uvnode *
fd_vget(int fd, int bsize, int segsize, int nseg)
{
struct fdfs *fs;
struct uvnode *vp;
int i;
fs = (struct fdfs *)malloc(sizeof(*fs));
if (fs == NULL)
return NULL;
if (segsize > 0) {
fs->fd_bufp = (struct fd_buf *)malloc(nseg *
sizeof(struct fd_buf));
if (fs->fd_bufp == NULL) {
free(fs);
return NULL;
}
for (i = 0; i < nseg; i++) {
fs->fd_bufp[i].start = 0x0;
fs->fd_bufp[i].end = 0x0;
fs->fd_bufp[i].buf = (char *)malloc(segsize);
if (fs->fd_bufp[i].buf == NULL) {
while (--i >= 0)
free(fs->fd_bufp[i].buf);
free(fs->fd_bufp);
free(fs);
return NULL;
}
}
} else
fs->fd_bufp = NULL;
fs->fd_fd = fd;
fs->fd_bufc = nseg;
fs->fd_bufi = 0;
fs->fd_bsize = bsize;
fs->fd_ssize = segsize;
vp = (struct uvnode *) malloc(sizeof(*vp));
memset(vp, 0, sizeof(*vp));
vp->v_fd = fd;
vp->v_fs = fs;
vp->v_usecount = 0;
vp->v_strategy_op = fd_vop_strategy;
vp->v_bwrite_op = fd_vop_bwrite;
vp->v_bmap_op = fd_vop_bmap;
LIST_INIT(&vp->v_cleanblkhd);
LIST_INIT(&vp->v_dirtyblkhd);
vp->v_data = NULL;
return vp;
}
/*
* Deallocate a vnode.
*/
void
fd_reclaim(struct uvnode *vp)
{
int i;
struct ubuf *bp;
struct fdfs *fs;
LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
bremfree(bp);
buf_destroy(bp);
}
LIST_FOREACH(bp, &vp->v_cleanblkhd, b_vnbufs) {
bremfree(bp);
buf_destroy(bp);
}
fs = (struct fdfs *)vp->v_fs;
for (i = 0; i < fs->fd_bufc; i++)
free(fs->fd_bufp[i].buf);
free(fs->fd_bufp);
free(fs);
memset(vp, 0, sizeof(vp));
}
/*
* We won't be using that last segment after all.
*/
void
fd_release(struct uvnode *vp)
{
--((struct fdfs *)vp->v_fs)->fd_bufi;
}
/*
* Reset buffer pointer to first buffer.
*/
void
fd_release_all(struct uvnode *vp)
{
((struct fdfs *)vp->v_fs)->fd_bufi = 0;
}
/*
* Prepare a segment buffer which we will expect to read from.
*/
int
fd_preload(struct uvnode *vp, daddr_t start)
{
struct fdfs *fs = (struct fdfs *)vp->v_fs;
struct fd_buf *t;
int r;
/* We might need to allocate more buffers. */
if (fs->fd_bufi == fs->fd_bufc) {
fs->fd_bufc = fs->fd_bufi + 1;
syslog(LOG_DEBUG, "increasing number of segment buffers to %d",
fs->fd_bufc);
t = realloc(fs->fd_bufp, fs->fd_bufc * sizeof(struct fd_buf));
if (t == NULL)
return -1;
fs->fd_bufp = t;
fs->fd_bufp[fs->fd_bufi].start = 0x0;
fs->fd_bufp[fs->fd_bufi].end = 0x0;
fs->fd_bufp[fs->fd_bufi].buf = (char *)malloc(fs->fd_ssize);
if (fs->fd_bufp[fs->fd_bufi].buf == NULL) {
--fs->fd_bufc;
free(fs->fd_bufp[fs->fd_bufc].buf);
}
}
/* Read the current buffer. */
fs->fd_bufp[fs->fd_bufi].start = start;
fs->fd_bufp[fs->fd_bufi].end = start + fs->fd_ssize / fs->fd_bsize;
if ((r = pread(fs->fd_fd, fs->fd_bufp[fs->fd_bufi].buf,
(size_t)fs->fd_ssize, start * fs->fd_bsize)) < 0) {
syslog(LOG_ERR, "preload to segment buffer %d", fs->fd_bufi);
return r;
}
fs->fd_bufi = fs->fd_bufi + 1;
return 0;
}
/*
* Get a pointer to a block contained in one of the segment buffers,
* as if from bread() but avoiding the buffer cache.
*/
char *
fd_ptrget(struct uvnode *vp, daddr_t bn)
{
int i;
struct fdfs *fs;
fs = (struct fdfs *)vp->v_fs;
for (i = 0; i < fs->fd_bufc; i++) {
if (bn >= fs->fd_bufp[i].start && bn < fs->fd_bufp[i].end) {
return fs->fd_bufp[i].buf +
(bn - fs->fd_bufp[i].start) * fs->fd_bsize;
}
}
return NULL;
}
/*
* Strategy routine. We can read from the segment buffer if requested.
*/
int
fd_vop_strategy(struct ubuf * bp)
{
struct fdfs *fs;
char *cp;
int count;
fs = (struct fdfs *)bp->b_vp->v_fs;
if (bp->b_flags & B_READ) {
if ((cp = fd_ptrget(bp->b_vp, bp->b_blkno)) != NULL) {
free(bp->b_data);
bp->b_data = cp;
bp->b_flags |= (B_DONTFREE | B_DONE);
return 0;
}
count = pread(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
bp->b_blkno * fs->fd_bsize);
if (count == bp->b_bcount)
bp->b_flags |= B_DONE;
} else {
count = pwrite(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
bp->b_blkno * fs->fd_bsize);
if (count == 0) {
perror("pwrite");
return -1;
}
bp->b_flags &= ~B_DELWRI;
reassignbuf(bp, bp->b_vp);
}
return 0;
}
/*
* Delayed write.
*/
int
fd_vop_bwrite(struct ubuf * bp)
{
bp->b_flags |= B_DELWRI;
reassignbuf(bp, bp->b_vp);
brelse(bp);
return 0;
}
/*
* Map lbn to disk address. Since we are using the file
* descriptor as the "disk", the disk address is meaningless
* and we just return the block address.
*/
int
fd_vop_bmap(struct uvnode * vp, daddr_t lbn, daddr_t * daddrp)
{
*daddrp = lbn;
return 0;
}

View File

@ -0,0 +1,24 @@
struct fd_buf {
char *buf; /* The buffer itself */
daddr_t start; /* Start of this buffer */
daddr_t end; /* End of this buffer */
};
struct fdfs {
int fd_fd; /* The file descriptor */
int fd_bufc; /* Number of segment buffers */
int fd_bufi; /* Index to next segment buffer */
struct fd_buf *fd_bufp; /* The buffers */
off_t fd_bsize; /* block size */
off_t fd_ssize; /* segment size */
};
struct uvnode * fd_vget(int, int, int, int);
int fd_preload(struct uvnode *, daddr_t);
int fd_vop_strategy(struct ubuf *);
int fd_vop_bwrite(struct ubuf *);
int fd_vop_bmap(struct uvnode *, daddr_t, daddr_t *);
char *fd_ptrget(struct uvnode *, daddr_t);
void fd_reclaim(struct uvnode *);
void fd_release(struct uvnode *);
void fd_release_all(struct uvnode *);

View File

@ -1,4 +1,4 @@
.\" $NetBSD: lfs_cleanerd.8,v 1.13 2003/08/07 09:46:43 agc Exp $
.\" $NetBSD: lfs_cleanerd.8,v 1.14 2006/03/30 19:10:13 perseant Exp $
.\"
.\" Copyright (c) 1993
.\" The Regents of the University of California. All rights reserved.
@ -86,9 +86,7 @@ instead of system load.
Clean more aggressively when the system load is below the given threshhold.
The default threshhold is 0.2.
.It Fl m
Use mmap, rather than rereading the Ifile to update the cleaner's
knowledge of the filesystem.
Do not use this option.
Does nothing. This option is present for historical compatibility.
.It Fl n Ar number-of-segments
Clean this number of segments at a time: that is, pass this many
segments' blocks through a single call to lfs_markv, or, if

File diff suppressed because it is too large Load Diff

View File

@ -1,852 +0,0 @@
/* $NetBSD: library.c,v 1.46 2005/08/23 05:55:29 christos Exp $ */
/*-
* 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)library.c 8.3 (Berkeley) 5/24/95";
#else
__RCSID("$NetBSD: library.c,v 1.46 2005/08/23 05:55:29 christos Exp $");
#endif
#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/fstypes.h>
#include <sys/mman.h>
#include <ufs/ufs/dinode.h>
#include <ufs/lfs/lfs.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include "clean.h"
void add_blocks(FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
daddr_t, daddr_t);
void add_inodes(FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
daddr_t);
int bi_compare(const void *, const void *);
int bi_toss(const void *, const void *, const void *);
void get_ifile(FS_INFO *, int);
int get_superblock(FS_INFO *, struct lfs *);
int pseg_valid(FS_INFO *, SEGSUM *, daddr_t);
int pseg_size(daddr_t, FS_INFO *, SEGSUM *);
extern int debug;
extern u_long cksum(void *, size_t); /* XXX */
int ifile_fd = -1;
static int dev_fd = -1;
/*
* 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(struct statvfs **buf, char *name, const char *type)
{
/* allocate space for the filesystem info */
if ((*buf = malloc(sizeof(struct statvfs))) == NULL)
return 0;
/* grab the filesystem info */
if (ifile_fd == -1) {
if (statvfs(name, *buf) == -1)
goto bad;
} else if(fstatvfs(ifile_fd, *buf) == -1)
goto bad;
/* check to see if it's the one we want */
if (strncmp(type, (*buf)->f_fstypename, MFSNAMELEN) ||
strncmp(name, (*buf)->f_mntonname, MNAMELEN))
goto bad;
return 1;
bad:
free(*buf);
return 0;
}
/*
* 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(struct statvfs *lstatvfsp, int use_mmap)
{
FS_INFO *fsp;
if ((fsp = malloc(sizeof(FS_INFO))) == NULL)
return NULL;
memset(fsp, 0, sizeof(FS_INFO));
fsp->fi_statvfsp = lstatvfsp;
if (get_superblock(fsp, &fsp->fi_lfs)) {
log_exit(0, LOG_ERR, "get_fs_info: get_superblock failed (%m)");
}
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 (statvfs) info.
*/
void
reread_fs_info(FS_INFO *fsp, int use_mmap)
{
if (ifile_fd != -1) {
if (fstatvfs(ifile_fd, fsp->fi_statvfsp) == -1)
log_exit(EBADF, LOG_ERR, "reread_fs_info: fstatvfs failed (%m)");
} else if (statvfs(fsp->fi_statvfsp->f_mntonname, fsp->fi_statvfsp)) {
log_exit(EBADF, LOG_ERR, "reread_fs_info: "
"fstatvfs `%s' failed (%m)",
fsp->fi_statvfsp->f_mntonname);
}
get_ifile(fsp, use_mmap);
}
static int
getdevfd(FS_INFO *fsp)
{
char rdev[MNAMELEN];
if (dev_fd != -1)
return dev_fd;
(void)snprintf(rdev, sizeof(rdev), "/dev/r%s",
fsp->fi_statvfsp->f_mntfromname + 5);
if ((dev_fd = open(rdev, O_RDONLY)) == -1)
log_exit(0, LOG_ERR, "Cannot open `%s' (%m)", rdev);
return dev_fd;
}
/*
* Read a block from disk.
*/
int
get_rawblock(FS_INFO *fsp, char *buf, size_t size, daddr_t daddr)
{
return pread(getdevfd(fsp), buf, size, fsbtob(&fsp->fi_lfs,
(off_t)daddr));
}
/*
* Read an inode from disk.
*/
struct ufs1_dinode *
get_dinode(FS_INFO *fsp, ino_t ino)
{
static struct ufs1_dinode dino;
struct ufs1_dinode *dip, *dib;
struct lfs *lfsp;
BLOCK_INFO bi;
lfsp = &fsp->fi_lfs;
/*
* Locate the inode block and find the inode.
* Use this to know how large the file is.
*/
memset(&bi, 0, sizeof(bi));
bi.bi_inode = ino;
bi.bi_lbn = LFS_UNUSED_LBN; /* We want the inode */
if (lfs_bmapv_emul(ifile_fd, &bi, 1) < 0) {
syslog(LOG_WARNING, "LIOCBMAPV: %m");
return NULL;
}
if (bi.bi_daddr <= 0)
return NULL;
lseek(getdevfd(fsp), (off_t)0, SEEK_SET);
if ((dib = malloc(lfsp->lfs_ibsize)) == NULL) {
syslog(LOG_WARNING, "get_dinode: malloc: %m");
return NULL;
}
pread(dev_fd, dib, lfsp->lfs_ibsize, fsbtob(lfsp, (off_t)bi.bi_daddr));
for (dip = dib; dip != dib + lfsp->lfs_inopb; ++dip)
if (dip->di_u.inumber == ino)
break;
if (dip == dib + lfsp->lfs_inopb) {
free(dib);
syslog(LOG_WARNING, "dinode %llu not found at fsb 0x%x",
(unsigned long long)ino, bi.bi_daddr);
return NULL;
}
dino = *dip; /* structure copy */
free(dib);
return &dino;
}
/*
* Gets the superblock from disk (possibly in face of errors)
*/
int
get_superblock(FS_INFO *fsp, struct lfs *sbp)
{
char buf[LFS_SBPAD];
static off_t sboff = LFS_LABELPAD;
lseek(getdevfd(fsp), 0, SEEK_SET);
for (;;) {
get(dev_fd, sboff, buf, LFS_SBPAD);
memcpy(&(sbp->lfs_dlfs), buf, sizeof(struct dlfs));
if (sboff == LFS_LABELPAD && fsbtob(sbp, 1) > LFS_LABELPAD)
sboff = fsbtob(sbp, (off_t)sbp->lfs_sboffs[0]);
else
break;
}
/* Compatibility */
if (sbp->lfs_version < 2) {
sbp->lfs_sumsize = LFS_V1_SUMMARY_SIZE;
sbp->lfs_ibsize = sbp->lfs_bsize;
sbp->lfs_start = sbp->lfs_sboffs[0];
sbp->lfs_tstamp = sbp->lfs_otstamp;
sbp->lfs_fsbtodb = 0;
}
return (0);
}
/*
* This function will map the ifile into memory. It causes a
* fatal error on failure.
*/
void
get_ifile(FS_INFO *fsp, int use_mmap)
{
struct fhandle fh;
struct stat file_stat;
caddr_t ifp;
int count;
int rfd; /* Root file descriptor */
static int oldnseg;
ifp = NULL;
if(ifile_fd == -1) {
rfd = open(fsp->fi_statvfsp->f_mntonname, O_RDONLY);
if (rfd < 0)
log_exit(0, LOG_ERR, "get_ifile: cannot open %s: %m",
fsp->fi_statvfsp->f_mntonname);
if (fcntl(rfd, LFCNIFILEFH, &fh) == -1)
log_exit(EOPNOTSUPP, LOG_ERR,
"get_ifile: fcntl LFCNIFILEFH on %s: %m",
fsp->fi_statvfsp->f_mntonname);
if ((ifile_fd = fhopen(&fh, O_RDONLY)) < 0)
log_exit(0, LOG_ERR,
"get_ifile: cannot fhopen ifile from %s: %m",
fsp->fi_statvfsp->f_mntonname);
close(rfd);
} else
lseek(ifile_fd, (off_t)0, SEEK_SET);
if (fstat(ifile_fd, &file_stat) == -1)
log_exit(EBADF, LOG_ERR, "get_ifile: fstat failed: %m");
fsp->fi_fs_tstamp = file_stat.st_mtimespec.tv_sec;
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);
/* XXX KS - Do we ever *write* to the ifile? */
ifp = mmap((caddr_t)0, file_stat.st_size,
PROT_READ, MAP_FILE|MAP_PRIVATE, ifile_fd, (off_t)0);
if (ifp == (caddr_t)(-1))
log_exit(0, LOG_ERR, "get_ifile: mmap failed (%m)");
} else {
if (fsp->fi_cip)
free(fsp->fi_cip);
if ((ifp = malloc(file_stat.st_size)) == NULL)
log_exit(0, LOG_ERR, "get_ifile: malloc failed (%m)");
redo_read:
count = read(ifile_fd, ifp, (size_t)file_stat.st_size);
if (count < 0)
log_exit(EIO, LOG_ERR, "get_ifile: bad read (%m)");
else if (count < file_stat.st_size) {
syslog(LOG_WARNING, "get_ifile (%m)");
if (lseek(ifile_fd, 0, SEEK_SET) < 0)
log_exit(0, LOG_ERR,
"get_ifile: bad ifile lseek (%m)");
goto redo_read;
}
}
fsp->fi_ifile_length = file_stat.st_size;
fsp->fi_cip = (CLEANERINFO *)ifp;
fsp->fi_segusep = (SEGUSE *)(ifp + CLEANSIZE(fsp));
fsp->fi_ifilep = (IFILE *)((caddr_t)fsp->fi_segusep + SEGTABSIZE(fsp));
/* If the number of segments changed under us, bomb out */
if (oldnseg && oldnseg != fsp->fi_cip->clean + fsp->fi_cip->dirty)
log_exit(0, LOG_NOTICE, "number of segments changed");
oldnseg = fsp->fi_cip->clean + fsp->fi_cip->dirty;
/*
* The number of ifile entries is equal to the number of
* 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;
}
/*
* Return the size of the partial segment, in bytes.
*/
int
pseg_size(daddr_t pseg_addr, FS_INFO *fsp, SEGSUM *sp)
{
int i, ssize = 0;
struct lfs *lfsp;
FINFO *fp;
lfsp = &fsp->fi_lfs;
ssize = lfsp->lfs_sumsize
+ howmany(sp->ss_ninos, INOPB(lfsp)) * lfsp->lfs_ibsize;
if (lfsp->lfs_version == 1)
fp = (FINFO *)(((char *)sp) + sizeof(SEGSUM_V1));
else
fp = (FINFO *)(sp + 1);
for (i = 0; i < sp->ss_nfinfo; ++i) {
ssize += (fp->fi_nblocks-1) * lfsp->lfs_bsize
+ fp->fi_lastlength;
fp = (FINFO *)(&fp->fi_blocks[fp->fi_nblocks]);
}
return ssize;
}
/*
* 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(FS_INFO *fsp, int seg, caddr_t seg_buf, BLOCK_INFO **blocks, int *bcount)
{
BLOCK_INFO *bip, *_bip, *nbip;
SEGSUM *sp;
SEGUSE *sup;
FINFO *fip;
struct lfs *lfsp;
caddr_t s;
daddr_t pseg_addr, seg_addr;
int nelem, nblocks, nsegs, sumsize, i, ssize;
i = 0;
bip = NULL;
lfsp = &fsp->fi_lfs;
nelem = 2 * segtod(lfsp, 1);
if (!(bip = malloc(nelem * sizeof(BLOCK_INFO)))) {
syslog(LOG_DEBUG, "couldn't allocate %ld bytes in lfs_segmapv",
(long)(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 = sntod(lfsp, seg);
pseg_addr = seg_addr + (sup->su_flags & SEGUSE_SUPERBLOCK ?
btofsb(lfsp, LFS_SBPAD) : 0);
if (seg == 0 && lfsp->lfs_version > 1) {
if (fsbtob(lfsp, pseg_addr) < LFS_LABELPAD + LFS_SBPAD) {
pseg_addr = btofsb(lfsp, LFS_LABELPAD + LFS_SBPAD);
s = seg_buf + LFS_LABELPAD + LFS_SBPAD;
syslog(LOG_DEBUG, "adj segment 0 offset to 0x%llx\n",
(long long)pseg_addr);
}
}
if(debug > 1)
syslog(LOG_DEBUG, "\tsegment buffer at: %p\tseg_addr 0x%llx", s,
(long long)seg_addr);
*bcount = 0;
for (nsegs = 0; nsegs < sup->su_nsums; nsegs++) {
sp = (SEGSUM *)s;
nblocks = pseg_valid(fsp, sp, pseg_addr);
if (nblocks <= 0) {
syslog(LOG_DEBUG, "Warning: invalid segment summary at 0x%llx",
(long long)pseg_addr);
goto err0;
}
#ifdef DIAGNOSTIC
/* Verify size of summary block */
sumsize = (lfsp->lfs_version == 1 ? sizeof(SEGSUM_V1) :
sizeof(SEGSUM)) +
(sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
if (lfsp->lfs_version == 1)
fip = (FINFO *)(((char *)sp) + sizeof(SEGSUM_V1));
else
fip = (FINFO *)(sp + 1);
for (i = 0; i < sp->ss_nfinfo; ++i) {
sumsize += sizeof(FINFO) +
(fip->fi_nblocks - 1) * sizeof(int32_t);
fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks]);
}
if (sumsize > lfsp->lfs_sumsize)
log_exit(0, LOG_ERR,
"Segment %d summary block too big: %d",
seg, sumsize);
#endif
if (*bcount + nblocks + sp->ss_ninos > nelem) {
nbip = realloc(bip, (*bcount + nblocks + sp->ss_ninos) *
sizeof(BLOCK_INFO));
if (!nbip)
goto err0;
bip = nbip;
nelem = *bcount + nblocks + sp->ss_ninos;
}
add_blocks(fsp, bip, bcount, sp, seg_buf, seg_addr, pseg_addr);
add_inodes(fsp, bip, bcount, sp, seg_buf, seg_addr);
ssize = pseg_size(pseg_addr, fsp, sp);
s += ssize;
pseg_addr += btofsb(lfsp, ssize);
}
if(nsegs < sup->su_nsums) {
syslog(LOG_WARNING,"only %d segment summaries in seg %d (expected %d)",
nsegs, seg, sup->su_nsums);
goto err0;
}
qsort(bip, *bcount, sizeof(BLOCK_INFO), bi_compare);
toss(bip, bcount, sizeof(BLOCK_INFO), bi_toss, NULL);
if(debug > 1) {
syslog(LOG_DEBUG, "BLOCK INFOS");
for (_bip = bip, i=0; i < *bcount; ++_bip, ++i)
PRINT_BINFO(_bip);
}
*blocks = bip;
return (0);
err0:
if (bip)
free(bip);
*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(FS_INFO *fsp, BLOCK_INFO *bip, int *countp, SEGSUM *sp,
caddr_t seg_buf, daddr_t segaddr, daddr_t psegaddr)
{
IFILE *ifp;
FINFO *fip;
caddr_t bp;
/* XXX ondisk32 */
int32_t *dp, *iaddrp;
int fsb_per_block, fsb_per_iblock, i, j;
int fsb_frag, iblks_seen;
u_long iblk_size, blk_size;
struct lfs *lfsp;
if(debug > 1)
syslog(LOG_DEBUG, "FILE INFOS");
lfsp = &fsp->fi_lfs;
fsb_per_block = fragstofsb(lfsp, lfsp->lfs_frag);
fsb_per_iblock = btofsb(lfsp, lfsp->lfs_ibsize);
blk_size = fsp->fi_lfs.lfs_bsize;
iblk_size = fsp->fi_lfs.lfs_ibsize;
bp = seg_buf + fsbtob(lfsp, psegaddr - segaddr) + lfsp->lfs_sumsize;
bip += *countp;
psegaddr += btofsb(lfsp, lfsp->lfs_sumsize);
/* XXX ondisk32 */
iaddrp = (int32_t *)((caddr_t)sp + lfsp->lfs_sumsize);
--iaddrp;
if (lfsp->lfs_version == 1)
fip = (FINFO *)(((char *)sp) + sizeof(SEGSUM_V1));
else
fip = (FINFO *)(sp + 1);
iblks_seen = 0;
for (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);
dp = &(fip->fi_blocks[0]);
for (j = 0; j < fip->fi_nblocks; j++, dp++) {
/* Skip over intervening inode blocks */
while (psegaddr == *iaddrp) {
/* syslog(LOG_DEBUG, "skipping ino block at 0x%x",
psegaddr); */
psegaddr += fsb_per_iblock;
bp += iblk_size;
--iaddrp;
}
bip->bi_inode = fip->fi_ino;
bip->bi_lbn = *dp;
bip->bi_daddr = psegaddr;
if (lfsp->lfs_version == 1)
bip->bi_segcreate = (time_t)(sp->ss_ident);
else
bip->bi_segcreate = (time_t)(sp->ss_create);
/* syslog(LOG_DEBUG, "ino %d lbn %d 0x%x %p",
bip->bi_inode, bip->bi_lbn, bip->bi_daddr,
bp); */
bip->bi_bp = bp;
bip->bi_version = ifp->if_version;
if (j < fip->fi_nblocks-1
|| fip->fi_lastlength == blk_size)
{
bip->bi_size = blk_size;
psegaddr += fsb_per_block;
bp += blk_size;
} else {
fsb_frag = fragstofsb(&(fsp->fi_lfs),
numfrags(&(fsp->fi_lfs),
fip->fi_lastlength));
if(debug > 1) {
syslog(LOG_DEBUG, "lastlength, frags: %d, %d",
fip->fi_lastlength, fsb_frag);
}
bip->bi_size = fip->fi_lastlength;
bp += fip->fi_lastlength;
psegaddr += fsb_frag;
}
if (ifp->if_version == fip->fi_version) {
++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(FS_INFO *fsp, BLOCK_INFO *bip, int *countp, SEGSUM *sp,
caddr_t seg_buf, daddr_t seg_addr)
{
struct ufs1_dinode *di = NULL; /* XXX gcc */
struct lfs *lfsp;
IFILE *ifp;
BLOCK_INFO *bp;
int32_t *daddrp;
ino_t inum;
int i;
if (sp->ss_ninos <= 0)
return;
bp = bip + *countp;
lfsp = &fsp->fi_lfs;
if(debug > 1)
syslog(LOG_DEBUG, "INODES:");
daddrp = (int32_t *)((caddr_t)sp + lfsp->lfs_sumsize);
for (i = 0; i < sp->ss_ninos; ++i) {
if (i % INOPB(lfsp) == 0) {
--daddrp;
di = (struct ufs1_dinode *)(seg_buf + fsbtob(lfsp,
*daddrp - seg_addr));
} else
++di;
inum = di->di_inumber;
bp->bi_lbn = LFS_UNUSED_LBN;
bp->bi_inode = inum;
bp->bi_daddr = *daddrp;
bp->bi_bp = di;
if (lfsp->lfs_version == 1)
bp->bi_segcreate = sp->ss_ident;
else
bp->bi_segcreate = sp->ss_create;
bp->bi_size = i; /* XXX KS - kludge */
if (inum == LFS_IFILE_INUM) {
PRINT_INODE(1, bp);
bp->bi_version = 1; /* Ifile version should be 1 */
bp++;
++(*countp);
} 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(FS_INFO *fsp, SEGSUM *ssp, daddr_t addr)
{
int nblocks;
#if 0
caddr_t p;
int i;
u_long *datap;
#endif
if (ssp->ss_magic != SS_MAGIC) {
syslog(LOG_WARNING, "Bad magic number: 0x%x instead of 0x%x", ssp->ss_magic, SS_MAGIC);
return(0);
}
if ((nblocks = dump_summary(&fsp->fi_lfs, ssp, 0, NULL, addr)) <= 0 ||
nblocks > (fsp->fi_lfs.lfs_ssize / fsp->fi_lfs.lfs_fsize) - 1)
return(0);
#if 0
/* check data/inode block(s) checksum too */
datap = (u_long *)malloc(nblocks * sizeof(u_long));
p = (caddr_t)ssp + lfsp->lfs_sumsize;
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) {
syslog(LOG_WARNING, "Bad data checksum");
free(datap);
return 0;
}
#endif
return (nblocks);
}
/* #define MMAP_SEGMENT */
/*
* read a segment into a memory buffer
*/
int
mmap_segment(FS_INFO *fsp, int segment, caddr_t *segbuf, int use_mmap)
{
struct lfs *lfsp;
daddr_t seg_daddr; /* base disk address of segment */
off_t seg_byte;
size_t ssize;
lfsp = &fsp->fi_lfs;
/* get the disk address of the beginning of the segment */
seg_daddr = sntod(lfsp, segment);
seg_byte = fsbtob(lfsp, (off_t)seg_daddr);
ssize = seg_size(lfsp);
lseek(getdevfd(fsp), 0, SEEK_SET);
if (use_mmap) {
*segbuf = mmap((caddr_t)0, seg_size(lfsp), PROT_READ,
MAP_FILE|MAP_SHARED, dev_fd, seg_byte);
if (*(long *)segbuf < 0) {
syslog(LOG_WARNING,"mmap_segment: mmap failed: %m");
return (0);
}
} else {
if(debug > 1)
syslog(LOG_DEBUG, "mmap_segment\tseg_daddr: %lu\tseg_size: %lu\tseg_offset: %llu",
(u_long)seg_daddr, (u_long)ssize, (long long)seg_byte);
/* malloc the space for the buffer */
*segbuf = malloc(ssize);
if (!*segbuf) {
syslog(LOG_WARNING,"mmap_segment: malloc failed: %m");
return (0);
}
/* read the segment data into the buffer */
if (lseek(dev_fd, seg_byte, SEEK_SET) != seg_byte) {
syslog(LOG_WARNING,"mmap_segment: bad lseek: %m");
free(*segbuf);
return (-1);
}
if (read(dev_fd, *segbuf, ssize) != ssize) {
syslog(LOG_WARNING,"mmap_segment: bad read: %m");
free(*segbuf);
return (-1);
}
}
/* close (fid); */
return (0);
}
void
munmap_segment(FS_INFO *fsp, caddr_t seg_buf, int use_mmap)
{
if (use_mmap)
munmap(seg_buf, seg_size(&fsp->fi_lfs));
else
free(seg_buf);
}
/*
* USEFUL DEBUGGING TOOLS:
*/
void
print_SEGSUM(struct lfs *lfsp, SEGSUM *p, daddr_t addr)
{
if (p)
(void) dump_summary(lfsp, p, DUMP_ALL, NULL, addr);
else
syslog(LOG_DEBUG, "0x0");
}
int
bi_compare(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_daddr - bb->bi_daddr)))
return (diff);
if(ba->bi_inode != LFS_IFILE_INUM && debug)
syslog(LOG_DEBUG,"bi_compare: using kludge on ino %llu!",
(unsigned long long)ba->bi_inode);
diff = ba->bi_size - bb->bi_size;
return diff;
}
int
bi_toss(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(void *p, int *nump, size_t size, int (*dotoss)(const void *, const void *, const void *), void *client)
{
int i;
char *p0, *p1;
if (*nump == 0)
return;
p0 = p;
for (i = *nump; --i > 0;) {
p1 = p0 + size;
if (dotoss(client, p0, p1)) {
memmove(p0, p1, i * size);
--(*nump);
} else
p0 += size;
}
}
void
log_exit(int gooderr, int pri, char *fmt, ...)
{
va_list ap;
int err;
err = errno;
if (err == gooderr)
pri = LOG_DEBUG;
va_start(ap, fmt);
vsyslog(pri, fmt, ap);
va_end(ap);
exit(err != gooderr);
}

View File

@ -1,76 +0,0 @@
/* $NetBSD: misc.c,v 1.8 2003/08/07 09:46:44 agc Exp $ */
/*-
* 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "from: @(#)misc.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: misc.c,v 1.8 2003/08/07 09:46:44 agc Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/mount.h>
#include <ufs/ufs/dinode.h>
#include <ufs/lfs/lfs.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include "clean.h"
extern char *special;
void
get(int fd, off_t off, void *p, size_t len)
{
int rbytes;
if (lseek(fd, off, SEEK_SET) < 0) {
syslog(LOG_ERR, "Exiting: %s: lseek: %m", special);
exit(1);
}
if ((rbytes = read(fd, p, len)) < 0) {
syslog(LOG_ERR, "Exiting: %s: read: %m", special);
exit(1);
}
if (rbytes != len) {
syslog(LOG_ERR, "Exiting: %s: short read (%d, not %ld)",
special, rbytes, (long)len);
exit(1);
}
}

View File

@ -1,286 +0,0 @@
/* $NetBSD: print.c,v 1.15 2003/08/07 09:46:44 agc Exp $ */
/*-
* 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "from: @(#)print.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: print.c,v 1.15 2003/08/07 09:46:44 agc Exp $");
#endif
#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 <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <syslog.h>
#include "clean.h"
extern int debug;
extern u_long cksum(void *, size_t); /* XXX */
/*
* 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.
*/
/* XXX ondisk32 */
int
dump_summary(struct lfs *lfsp, SEGSUM *sp, u_long flags, int32_t **iaddrp, daddr_t addr)
{
int i, j, blk, numblocks, accino=0;
/* XXX ondisk32 */
int32_t *dp, ddp, *idp;
u_int32_t *datap;
int size;
FINFO *fp;
u_int32_t ck;
blk=0;
datap = (u_int32_t *)malloc(segtod(lfsp, 1) * sizeof(u_int32_t));
if(datap==NULL) {
syslog(LOG_WARNING, "cannot allocate %d in dump_summary",
(int)(segtod(lfsp, 1) * sizeof(u_int32_t)));
return(-1);
}
if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum,
lfsp->lfs_sumsize - sizeof(sp->ss_sumsum)))) {
syslog(LOG_WARNING, "sumsum checksum mismatch: should be %d, found %d\n",
(int) sp->ss_sumsum, (int) ck);
free(datap);
return(-1);
}
if (flags & DUMP_SUM_HEADER) {
syslog(LOG_DEBUG, " %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 );
syslog(LOG_DEBUG, "\tcreate %s", ctime(
(lfsp->lfs_version == 1 ? (time_t *)&sp->ss_ident :
(time_t *)&sp->ss_create)));
}
numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
/* Dump out inode disk addresses */
if (flags & DUMP_INODE_ADDRS)
syslog(LOG_DEBUG, " Inode addresses:");
/* XXX ondisk32 */
idp = dp = (int32_t *)((caddr_t)sp + lfsp->lfs_sumsize);
--idp;
for (--dp, i = 0; i < howmany(sp->ss_ninos,INOPB(lfsp)); --dp) {
if (flags & DUMP_INODE_ADDRS)
syslog(LOG_DEBUG, "\t0x%lx", (u_long)*dp);
++i;
}
if (iaddrp) {
*iaddrp = dp;
}
ddp = addr + btofsb(lfsp, lfsp->lfs_sumsize);
if (lfsp->lfs_version == 1)
fp = (FINFO *)(((char *)sp) + sizeof(SEGSUM_V1));
else
fp = (FINFO *)(sp + 1);
for (i = 0; i < sp->ss_nfinfo; ++i) {
/* Add any intervening Inode blocks to our checksum array */
/* printf("finfo %d: ddp=%lx, *idp=%lx\n",i,ddp,*idp); */
while(ddp == *idp) {
/* printf(" [ino %lx]",ddp); */
datap[blk++] = *(u_int32_t*)((caddr_t)sp + fsbtob(lfsp, ddp-addr));
--idp;
ddp += btofsb(lfsp, lfsp->lfs_ibsize);
accino++;
}
for(j=0;j<fp->fi_nblocks;j++) {
if(j==fp->fi_nblocks-1) {
size = btofsb(lfsp, fp->fi_lastlength);
/* printf(" %lx:%d",ddp,size); */
} else {
size = btofsb(lfsp, lfsp->lfs_bsize);
/* printf(" %lx/%d",ddp,size); */
}
datap[blk++] = *(u_int32_t*)((caddr_t)sp + fsbtob(lfsp, ddp-addr));
ddp += size;
}
numblocks += fp->fi_nblocks;
if (flags & DUMP_FINFOS) {
syslog(LOG_DEBUG, " %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++) {
syslog(LOG_DEBUG, "\t%d", *dp);
}
} else
dp = &fp->fi_blocks[fp->fi_nblocks];
fp = (FINFO *)dp;
/* printf("\n"); */
}
/* Add lagging inode blocks too */
/* printf("end: ddp=%lx, *idp=%lx\n",ddp,*idp); */
while(*idp >= ddp && accino < howmany(sp->ss_ninos,INOPB(lfsp))) {
ddp = *idp;
/* printf(" [ino %lx]",ddp); */
datap[blk++] = *(u_int32_t*)((caddr_t)sp + fsbtob(lfsp, ddp-addr));
--idp;
accino++;
}
/* printf("\n"); */
if(accino != howmany(sp->ss_ninos,lfsp->lfs_inopb)) {
syslog(LOG_DEBUG,"Oops, given %d inodes got %d\n", howmany(sp->ss_ninos,lfsp->lfs_inopb), accino);
}
if(blk!=numblocks) {
syslog(LOG_DEBUG,"Oops, blk=%d numblocks=%d\n",blk,numblocks);
}
/* check data/inode block(s) checksum too */
if ((ck=cksum ((void *)datap, numblocks * sizeof(u_int32_t))) != sp->ss_datasum) {
syslog(LOG_DEBUG, "Bad data checksum: given %lu, got %lu",
(unsigned long)sp->ss_datasum, (unsigned long)ck);
free(datap);
return 0;
}
free(datap);
return (numblocks);
}
void
dump_cleaner_info(void *ipage)
{
CLEANERINFO *cip;
if(debug <= 1)
return;
cip = (CLEANERINFO *)ipage;
syslog(LOG_DEBUG,"segments clean\t%d\tsegments dirty\t%d\n\n",
cip->clean, cip->dirty);
}
void
dump_super(struct lfs *lfsp)
{
int i;
if(debug < 2)
return;
syslog(LOG_DEBUG,"%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);
syslog(LOG_DEBUG, "%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);
syslog(LOG_DEBUG, "%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);
syslog(LOG_DEBUG, "%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);
syslog(LOG_DEBUG, "%s0x%X\t%s%d\t%s0x%llX\t%s%lu\n",
"segmask ", lfsp->lfs_segmask,
"segshift ", lfsp->lfs_segshift,
"bmask ", (long long)lfsp->lfs_bmask,
"bshift ", (u_long)lfsp->lfs_bshift);
syslog(LOG_DEBUG, "%s0x%llX\t\t%s%lu\t%s0x%llX\t%s%lu\n",
"ffmask ", (long long)lfsp->lfs_ffmask,
"ffshift ", (u_long)lfsp->lfs_ffshift,
"fbmask ", (long long)lfsp->lfs_fbmask,
"fbshift ", (u_long)lfsp->lfs_fbshift);
syslog(LOG_DEBUG, "%s%d\t\t%s0x%X\t%s0x%llx\n",
"fsbtodb ", lfsp->lfs_fsbtodb,
"cksum ", lfsp->lfs_cksum,
"maxfilesize ", (long long)lfsp->lfs_maxfilesize);
syslog(LOG_DEBUG, "Superblock disk addresses:\t");
for (i = 0; i < LFS_MAXNUMSB; i++) {
syslog(LOG_DEBUG, " 0x%X", lfsp->lfs_sboffs[i]);
}
syslog(LOG_DEBUG, "Checkpoint Info\n");
syslog(LOG_DEBUG, "%s%d\t%s0x%X\t%s%d\n",
"freehd ", lfsp->lfs_freehd,
"idaddr ", lfsp->lfs_idaddr,
"ifile ", lfsp->lfs_ifile);
syslog(LOG_DEBUG, "%s%d\t%s%d\t%s%d\n",
"bfree ", lfsp->lfs_bfree,
"avail ", lfsp->lfs_avail,
"uinodes ", lfsp->lfs_uinodes);
syslog(LOG_DEBUG, "%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);
syslog(LOG_DEBUG, "tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp));
syslog(LOG_DEBUG, "\nIn-Memory Information\n");
syslog(LOG_DEBUG, "%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 );
syslog(LOG_DEBUG, "%s%d\t%s%d\t%s0x%X\t%s%d\n",
"nactive ", lfsp->lfs_nactive,
"fmod ", lfsp->lfs_fmod,
"pflags ", lfsp->lfs_pflags,
"ronly ", lfsp->lfs_ronly);
}