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:
parent
162bcf9406
commit
9c75397609
@ -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>
|
||||
|
@ -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
|
75
libexec/lfs_cleanerd/cleaner.h
Normal file
75
libexec/lfs_cleanerd/cleaner.h
Normal 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
227
libexec/lfs_cleanerd/cleansrv.c
Normal file
227
libexec/lfs_cleanerd/cleansrv.c
Normal 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 */
|
@ -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
283
libexec/lfs_cleanerd/fdfs.c
Normal 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;
|
||||
}
|
24
libexec/lfs_cleanerd/fdfs.h
Normal file
24
libexec/lfs_cleanerd/fdfs.h
Normal 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 *);
|
@ -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
|
||||
|
1469
libexec/lfs_cleanerd/lfs_cleanerd.c
Normal file
1469
libexec/lfs_cleanerd/lfs_cleanerd.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user