mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-04 09:09:56 +00:00
Additions to run checks on live filesystems. This change will not
affect current systems until fsck is modified to use these new facilities. To try out this change, set the fsck passno to zero in /etc/fstab to cause the filesystem to be mounted without running fsck, then run `fsck_ffs -p -B <filesystem>' after the system has been brought up multiuser to run a background cleanup on <filesystem>. Note that the <filesystem> in question must have soft updates enabled.
This commit is contained in:
parent
3fa18367c2
commit
7578c6ab98
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=74556
@ -41,6 +41,7 @@ static const char rcsid[] =
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
@ -53,7 +54,10 @@ static const char rcsid[] =
|
||||
|
||||
char *lfname = "lost+found";
|
||||
int lfmode = 01777;
|
||||
struct dirtemplate emptydir = { 0, DIRBLKSIZ };
|
||||
struct dirtemplate emptydir = {
|
||||
0, DIRBLKSIZ, DT_UNKNOWN, 0, "",
|
||||
0, 0, DT_UNKNOWN, 0, ""
|
||||
};
|
||||
struct dirtemplate dirhead = {
|
||||
0, 12, DT_DIR, 1, ".",
|
||||
0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
|
||||
@ -107,7 +111,7 @@ dirscan(idesc)
|
||||
{
|
||||
register struct direct *dp;
|
||||
register struct bufarea *bp;
|
||||
int dsize, n;
|
||||
u_int dsize, n;
|
||||
long blksiz;
|
||||
char dbuf[DIRBLKSIZ];
|
||||
|
||||
@ -324,7 +328,7 @@ adjust(idesc, lcnt)
|
||||
* in preen mode, and are on a filesystem using soft updates,
|
||||
* then just toss any partially allocated files.
|
||||
*/
|
||||
if (resolved && preen && usedsoftdep) {
|
||||
if (resolved && (preen || bkgrdflag) && usedsoftdep) {
|
||||
clri(idesc, "UNREF", 1);
|
||||
return;
|
||||
} else {
|
||||
@ -362,8 +366,19 @@ adjust(idesc, lcnt)
|
||||
printf(" (ADJUSTED)\n");
|
||||
}
|
||||
if (preen || reply("ADJUST") == 1) {
|
||||
dp->di_nlink -= lcnt;
|
||||
inodirty();
|
||||
if (bkgrdflag == 0) {
|
||||
dp->di_nlink -= lcnt;
|
||||
inodirty();
|
||||
} else {
|
||||
cmd.value = idesc->id_number;
|
||||
cmd.size = -lcnt;
|
||||
if (debug)
|
||||
printf("adjrefcnt ino %d amt %d\n",
|
||||
(long)cmd.value, cmd.size);
|
||||
if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
|
||||
&cmd, sizeof cmd) == -1)
|
||||
rwerror("ADJUST INODE", cmd.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -448,6 +463,10 @@ linkup(orphan, parentdir, name)
|
||||
pinode(orphan);
|
||||
if (preen && dp->di_size == 0)
|
||||
return (0);
|
||||
if (cursnapshot != 0) {
|
||||
pfatal("FILE LINKUP IN SNAPSHOT");
|
||||
return (0);
|
||||
}
|
||||
if (preen)
|
||||
printf(" (RECONNECTED)\n");
|
||||
else
|
||||
|
@ -102,14 +102,18 @@ struct bufarea cgblk; /* cylinder group blocks */
|
||||
struct bufarea *pdirbp; /* current directory contents */
|
||||
struct bufarea *pbp; /* current inode block */
|
||||
|
||||
#define dirty(bp) (bp)->b_dirty = 1
|
||||
#define dirty(bp) \
|
||||
if (fswritefd < 0) \
|
||||
pfatal("SETTING DIRTY FLAG IN READ_ONLY MODE\n"); \
|
||||
else \
|
||||
(bp)->b_dirty = 1
|
||||
#define initbarea(bp) \
|
||||
(bp)->b_dirty = 0; \
|
||||
(bp)->b_bno = (ufs_daddr_t)-1; \
|
||||
(bp)->b_flags = 0;
|
||||
|
||||
#define sbdirty() sblk.b_dirty = 1
|
||||
#define cgdirty() cgblk.b_dirty = 1
|
||||
#define sbdirty() dirty(&sblk)
|
||||
#define cgdirty() dirty(&cgblk)
|
||||
#define sblock (*sblk.b_un.b_fs)
|
||||
#define cgrp (*cgblk.b_un.b_cg)
|
||||
|
||||
@ -188,12 +192,21 @@ struct inoinfo {
|
||||
long numdirs, dirhash, listmax, inplast;
|
||||
long countdirs; /* number of directories we actually found */
|
||||
|
||||
#define MIBSIZE 3 /* size of fsck sysctl MIBs */
|
||||
int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */
|
||||
int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */
|
||||
int freefiles[MIBSIZE]; /* MIB command to free a set of files */
|
||||
int freedirs[MIBSIZE]; /* MIB command to free a set of directories */
|
||||
int freeblks[MIBSIZE]; /* MIB command to free a set of data blocks */
|
||||
struct fsck_cmd cmd; /* sysctl filesystem update commands */
|
||||
char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
|
||||
char *cdevname; /* name of device being checked */
|
||||
long dev_bsize; /* computed value of DEV_BSIZE */
|
||||
long secsize; /* actual disk sector size */
|
||||
char fflag; /* force check, ignore clean flag */
|
||||
char nflag; /* assume a no response */
|
||||
char yflag; /* assume a yes response */
|
||||
int bkgrdflag; /* use a snapshot to run on an active system */
|
||||
int bflag; /* location of alternate super block */
|
||||
int debug; /* output debugging info */
|
||||
int cvtlevel; /* convert to newer file system format */
|
||||
@ -205,7 +218,6 @@ char preen; /* just fix normal inconsistencies */
|
||||
char rerun; /* rerun fsck. Only used in non-preen mode */
|
||||
int returntosingle; /* 1 => return to single user mode on exit */
|
||||
char resolved; /* cleared if unresolved changes => not clean */
|
||||
int markclean; /* mark file system clean when done */
|
||||
char havesb; /* superblock has been read */
|
||||
char skipclean; /* skip clean file systems if preening */
|
||||
int fsmodified; /* 1 => write done to file system */
|
||||
@ -302,6 +314,7 @@ void pinode __P((ino_t ino));
|
||||
void propagate __P((void));
|
||||
void pwarn __P((const char *fmt, ...));
|
||||
int reply __P((char *question));
|
||||
void rwerror __P((char *mesg, ufs_daddr_t blk));
|
||||
void setinodebuf __P((ino_t));
|
||||
int setup __P((char *dev));
|
||||
void voidquit __P((int));
|
||||
|
@ -60,8 +60,6 @@ static const char rcsid[] =
|
||||
|
||||
long diskreads, totalreads; /* Disk cache statistics */
|
||||
|
||||
static void rwerror __P((char *mesg, ufs_daddr_t blk));
|
||||
|
||||
int
|
||||
ftypeok(dp)
|
||||
struct dinode *dp;
|
||||
@ -95,7 +93,7 @@ reply(question)
|
||||
pfatal("INTERNAL ERROR: GOT TO reply()");
|
||||
persevere = !strcmp(question, "CONTINUE");
|
||||
printf("\n");
|
||||
if (!persevere && (nflag || fswritefd < 0)) {
|
||||
if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) {
|
||||
printf("%s? no\n\n", question);
|
||||
resolved = 0;
|
||||
return (0);
|
||||
@ -239,11 +237,15 @@ flush(fd, bp)
|
||||
|
||||
if (!bp->b_dirty)
|
||||
return;
|
||||
bp->b_dirty = 0;
|
||||
if (fswritefd < 0) {
|
||||
pfatal("WRITING IN READ_ONLY MODE.\n");
|
||||
return;
|
||||
}
|
||||
if (bp->b_errs != 0)
|
||||
pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
|
||||
(bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
|
||||
bp->b_bno);
|
||||
bp->b_dirty = 0;
|
||||
bp->b_errs = 0;
|
||||
bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
|
||||
if (bp != &sblk)
|
||||
@ -256,7 +258,7 @@ flush(fd, bp)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
rwerror(mesg, blk)
|
||||
char *mesg;
|
||||
ufs_daddr_t blk;
|
||||
@ -264,7 +266,7 @@ rwerror(mesg, blk)
|
||||
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
pfatal("CANNOT %s: BLK %ld", mesg, blk);
|
||||
pfatal("CANNOT %s: %ld", mesg, blk);
|
||||
if (reply("CONTINUE") == 0)
|
||||
exit(EEXIT);
|
||||
}
|
||||
@ -276,12 +278,31 @@ ckfini(markclean)
|
||||
register struct bufarea *bp, *nbp;
|
||||
int ofsmodified, cnt = 0;
|
||||
|
||||
if (bkgrdflag) {
|
||||
unlink(snapname);
|
||||
if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) {
|
||||
cmd.value = FS_UNCLEAN;
|
||||
cmd.size = markclean ? -1 : 1;
|
||||
if (sysctlbyname("vfs.ffs.setflags", 0, 0,
|
||||
&cmd, sizeof cmd) == -1)
|
||||
rwerror("SET FILESYSTEM FLAGS", FS_UNCLEAN);
|
||||
if (!preen) {
|
||||
printf("\n***** FILE SYSTEM MARKED %s *****\n",
|
||||
markclean ? "CLEAN" : "DIRTY");
|
||||
if (!markclean)
|
||||
rerun = 1;
|
||||
}
|
||||
} else if (!preen && !markclean) {
|
||||
printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
|
||||
rerun = 1;
|
||||
}
|
||||
}
|
||||
if (fswritefd < 0) {
|
||||
(void)close(fsreadfd);
|
||||
return;
|
||||
}
|
||||
flush(fswritefd, &sblk);
|
||||
if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
|
||||
if (havesb && sblk.b_bno != SBOFF / dev_bsize && cursnapshot == 0 &&
|
||||
!preen && reply("UPDATE STANDARD SUPERBLOCK")) {
|
||||
sblk.b_bno = SBOFF / dev_bsize;
|
||||
sbdirty();
|
||||
@ -299,7 +320,7 @@ ckfini(markclean)
|
||||
if (bufhead.b_size != cnt)
|
||||
errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt);
|
||||
pbp = pdirbp = (struct bufarea *)0;
|
||||
if (sblock.fs_clean != markclean) {
|
||||
if (cursnapshot == 0 && sblock.fs_clean != markclean) {
|
||||
sblock.fs_clean = markclean;
|
||||
sbdirty();
|
||||
ofsmodified = fsmodified;
|
||||
@ -336,12 +357,12 @@ bread(fd, buf, blk, size)
|
||||
offset = blk;
|
||||
offset *= dev_bsize;
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
rwerror("SEEK BLK", blk);
|
||||
else if (read(fd, buf, (int)size) == size)
|
||||
return (0);
|
||||
rwerror("READ", blk);
|
||||
rwerror("READ BLK", blk);
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
rwerror("SEEK BLK", blk);
|
||||
errs = 0;
|
||||
memset(buf, 0, (size_t)size);
|
||||
printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
|
||||
@ -379,15 +400,15 @@ bwrite(fd, buf, blk, size)
|
||||
offset = blk;
|
||||
offset *= dev_bsize;
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
rwerror("SEEK BLK", blk);
|
||||
else if (write(fd, buf, (int)size) == size) {
|
||||
fsmodified = 1;
|
||||
return;
|
||||
}
|
||||
resolved = 0;
|
||||
rwerror("WRITE", blk);
|
||||
rwerror("WRITE BLK", blk);
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
rwerror("SEEK BLK", blk);
|
||||
printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
|
||||
for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
|
||||
if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
|
||||
|
@ -41,6 +41,7 @@ static const char rcsid[] =
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
@ -187,7 +188,9 @@ iblock(idesc, ilevel, isize)
|
||||
continue;
|
||||
(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
|
||||
(u_long)idesc->id_number);
|
||||
if (dofix(idesc, buf)) {
|
||||
if (usedsoftdep) {
|
||||
pfatal(buf);
|
||||
} else if (dofix(idesc, buf)) {
|
||||
*ap = 0;
|
||||
dirty(bp);
|
||||
}
|
||||
@ -481,10 +484,21 @@ clri(idesc, type, flag)
|
||||
if (preen)
|
||||
printf(" (CLEARED)\n");
|
||||
n_files--;
|
||||
(void)ckinode(dp, idesc);
|
||||
clearinode(dp);
|
||||
inoinfo(idesc->id_number)->ino_state = USTATE;
|
||||
inodirty();
|
||||
if (bkgrdflag == 0) {
|
||||
(void)ckinode(dp, idesc);
|
||||
inoinfo(idesc->id_number)->ino_state = USTATE;
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
} else {
|
||||
cmd.value = idesc->id_number;
|
||||
cmd.size = -dp->di_nlink;
|
||||
if (debug)
|
||||
printf("adjrefcnt ino %d amt %d\n",
|
||||
(long)cmd.value, cmd.size);
|
||||
if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
|
||||
&cmd, sizeof cmd) == -1)
|
||||
rwerror("ADJUST INODE", cmd.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,8 +83,7 @@ main(argc, argv)
|
||||
|
||||
sync();
|
||||
skipclean = 1;
|
||||
markclean = 1;
|
||||
while ((ch = getopt(argc, argv, "b:c:dfm:npy")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "b:Bc:dfm:npy")) != -1) {
|
||||
switch (ch) {
|
||||
case 'b':
|
||||
skipclean = 0;
|
||||
@ -92,6 +91,10 @@ main(argc, argv)
|
||||
printf("Alternate super block location: %d\n", bflag);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
bkgrdflag = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
skipclean = 0;
|
||||
cvtlevel = argtoi('c', "conversion level", optarg, 10);
|
||||
@ -183,9 +186,12 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
int child;
|
||||
{
|
||||
ufs_daddr_t n_ffree, n_bfree;
|
||||
struct ufs_args args;
|
||||
struct dups *dp;
|
||||
struct statfs *mntbuf;
|
||||
struct statfs *mntp;
|
||||
struct zlncnt *zlnp;
|
||||
ufs_daddr_t blks;
|
||||
ufs_daddr_t files;
|
||||
int cylno;
|
||||
|
||||
if (preen && child)
|
||||
@ -193,6 +199,44 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
cdevname = filesys;
|
||||
if (debug && preen)
|
||||
pwarn("starting\n");
|
||||
|
||||
/*
|
||||
* If we are to do a background check:
|
||||
* Get the mount point information of the filesystem
|
||||
* create snapshot file
|
||||
* return created snapshot file
|
||||
* if not found, clear bkgrdflag and proceed with normal fsck
|
||||
*/
|
||||
mntp = getmntpt(filesys);
|
||||
if (bkgrdflag) {
|
||||
if (mntp == NULL) {
|
||||
bkgrdflag = 0;
|
||||
pwarn("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n");
|
||||
} else if ((mntp->f_flags & MNT_SOFTDEP) == 0) {
|
||||
bkgrdflag = 0;
|
||||
pwarn("NOT USING SOFT UPDATES, CANNOT RUN IN BACKGROUND\n");
|
||||
} else if ((mntp->f_flags & MNT_RDONLY) != 0) {
|
||||
bkgrdflag = 0;
|
||||
pwarn("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n");
|
||||
} else {
|
||||
snprintf(snapname, sizeof snapname, "%s/.fsck_snapshot",
|
||||
mntp->f_mntonname);
|
||||
args.fspec = snapname;
|
||||
while (mount("ffs", mntp->f_mntonname,
|
||||
mntp->f_flags | MNT_UPDATE | MNT_SNAPSHOT,
|
||||
&args) < 0) {
|
||||
if (errno == EEXIST && unlink(snapname) == 0)
|
||||
continue;
|
||||
bkgrdflag = 0;
|
||||
pwarn("CANNOT CREATE SNAPSHOT %s: %s\n",
|
||||
snapname, strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (bkgrdflag != 0)
|
||||
filesys = snapname;
|
||||
}
|
||||
}
|
||||
|
||||
switch (setup(filesys)) {
|
||||
case 0:
|
||||
if (preen)
|
||||
@ -206,12 +250,6 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
sblock.fs_cstotal.cs_nffree * 100.0 / sblock.fs_dsize);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the mount point information of the filesystem, if
|
||||
* it is available.
|
||||
*/
|
||||
mntbuf = getmntpt(filesys);
|
||||
|
||||
/*
|
||||
* Cleared if any questions answered no. Used to decide if
|
||||
@ -223,7 +261,7 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
*/
|
||||
if (preen == 0) {
|
||||
printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
|
||||
if (mntbuf != NULL && mntbuf->f_flags & MNT_ROOTFS)
|
||||
if (mntp != NULL && mntp->f_flags & MNT_ROOTFS)
|
||||
printf("** Root file system\n");
|
||||
printf("** Phase 1 - Check Blocks and Sizes\n");
|
||||
}
|
||||
@ -272,20 +310,26 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
*/
|
||||
n_ffree = sblock.fs_cstotal.cs_nffree;
|
||||
n_bfree = sblock.fs_cstotal.cs_nbfree;
|
||||
files = maxino - ROOTINO - sblock.fs_cstotal.cs_nifree - n_files;
|
||||
blks = n_blks +
|
||||
sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
|
||||
blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
|
||||
blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
blks = maxfsblock - (n_ffree + sblock.fs_frag * n_bfree) - blks;
|
||||
if (bkgrdflag && (files > 0 || blks > 0)) {
|
||||
countdirs = sblock.fs_cstotal.cs_ndir - countdirs;
|
||||
pwarn("Reclaimed: %d directories, %d files, %d fragments\n",
|
||||
countdirs, files - countdirs, blks);
|
||||
}
|
||||
pwarn("%ld files, %ld used, %ld free ",
|
||||
n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
|
||||
printf("(%d frags, %d blocks, %.1f%% fragmentation)\n",
|
||||
n_ffree, n_bfree, n_ffree * 100.0 / sblock.fs_dsize);
|
||||
if (debug &&
|
||||
(n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
|
||||
printf("%d files missing\n", n_files);
|
||||
if (debug) {
|
||||
n_blks += sblock.fs_ncg *
|
||||
(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
|
||||
n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
|
||||
n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
|
||||
printf("%d blocks missing\n", n_blks);
|
||||
if (files < 0)
|
||||
printf("%d inodes missing\n", -files);
|
||||
if (blks < 0)
|
||||
printf("%d blocks missing\n", -blks);
|
||||
if (duplist != NULL) {
|
||||
printf("The following duplicate blocks remain:");
|
||||
for (dp = duplist; dp; dp = dp->next)
|
||||
@ -321,7 +365,7 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
/*
|
||||
* Check to see if the filesystem is mounted read-write.
|
||||
*/
|
||||
if (mntbuf != NULL && (mntbuf->f_flags & MNT_RDONLY) == 0)
|
||||
if (bkgrdflag == 0 && mntp != NULL && (mntp->f_flags & MNT_RDONLY) == 0)
|
||||
resolved = 0;
|
||||
ckfini(resolved);
|
||||
|
||||
@ -334,7 +378,7 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
|
||||
if (rerun)
|
||||
printf("\n***** PLEASE RERUN FSCK *****\n");
|
||||
if (mntbuf != NULL) {
|
||||
if (mntp != NULL) {
|
||||
struct ufs_args args;
|
||||
int ret;
|
||||
/*
|
||||
@ -342,16 +386,16 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
* it unless it is read-write, so we can continue using it
|
||||
* as safely as possible.
|
||||
*/
|
||||
if (mntbuf->f_flags & MNT_RDONLY) {
|
||||
if (mntp->f_flags & MNT_RDONLY) {
|
||||
args.fspec = 0;
|
||||
args.export.ex_flags = 0;
|
||||
args.export.ex_root = 0;
|
||||
ret = mount("ufs", mntbuf->f_mntonname,
|
||||
mntbuf->f_flags | MNT_UPDATE | MNT_RELOAD, &args);
|
||||
ret = mount("ufs", mntp->f_mntonname,
|
||||
mntp->f_flags | MNT_UPDATE | MNT_RELOAD, &args);
|
||||
if (ret == 0)
|
||||
return (0);
|
||||
pwarn("mount reload of '%s' failed: %s\n\n",
|
||||
mntbuf->f_mntonname, strerror(errno));
|
||||
mntp->f_mntonname, strerror(errno));
|
||||
}
|
||||
if (!fsmodified)
|
||||
return (0);
|
||||
|
@ -41,6 +41,7 @@ static const char rcsid[] =
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
@ -265,7 +266,7 @@ checkinode(inumber, idesc)
|
||||
* Fake ndb value so direct/indirect block checks below
|
||||
* will detect any garbage after symlink string.
|
||||
*/
|
||||
if (dp->di_size < sblock.fs_maxsymlinklen) {
|
||||
if (dp->di_size < (u_int64_t)sblock.fs_maxsymlinklen) {
|
||||
ndb = howmany(dp->di_size, sizeof(ufs_daddr_t));
|
||||
if (ndb > NDADDR) {
|
||||
j = ndb - NDADDR;
|
||||
@ -343,9 +344,20 @@ checkinode(inumber, idesc)
|
||||
printf(" (CORRECTED)\n");
|
||||
else if (reply("CORRECT") == 0)
|
||||
return;
|
||||
dp = ginode(inumber);
|
||||
dp->di_blocks = idesc->id_entryno;
|
||||
inodirty();
|
||||
if (bkgrdflag == 0) {
|
||||
dp = ginode(inumber);
|
||||
dp->di_blocks = idesc->id_entryno;
|
||||
inodirty();
|
||||
} else {
|
||||
cmd.value = idesc->id_number;
|
||||
cmd.size = idesc->id_entryno - dp->di_blocks;
|
||||
if (debug)
|
||||
printf("adjblkcnt ino %d amount %d\n",
|
||||
(long)cmd.value, cmd.size);
|
||||
if (sysctl(adjblkcnt, MIBSIZE, 0, 0,
|
||||
&cmd, sizeof cmd) == -1)
|
||||
rwerror("ADJUST INODE BLOCK COUNT", cmd.value);
|
||||
}
|
||||
}
|
||||
return;
|
||||
unknown:
|
||||
|
@ -43,6 +43,7 @@ static const char rcsid[] =
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <string.h>
|
||||
@ -444,6 +445,8 @@ pass2check(idesc)
|
||||
pwarn("%s %s %s\n", pathbuf,
|
||||
"IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
|
||||
namebuf);
|
||||
if (cursnapshot != 0)
|
||||
break;
|
||||
if (preen) {
|
||||
printf(" (REMOVED)\n");
|
||||
n = 1;
|
||||
|
@ -78,7 +78,8 @@ pass3()
|
||||
* them in DSTATE which will cause them to be pitched
|
||||
* in pass 4.
|
||||
*/
|
||||
if (preen && resolved && usedsoftdep && state == DSTATE) {
|
||||
if ((preen || bkgrdflag) &&
|
||||
resolved && usedsoftdep && state == DSTATE) {
|
||||
if (inp->i_dotdot >= ROOTINO)
|
||||
inoinfo(inp->i_dotdot)->ino_linkcnt++;
|
||||
continue;
|
||||
|
@ -40,6 +40,7 @@ static const char rcsid[] =
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
@ -49,16 +50,18 @@ static const char rcsid[] =
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
static void check_maps __P((u_char *, u_char *, int, int, char *, int *,
|
||||
int, int));
|
||||
|
||||
void
|
||||
pass5()
|
||||
{
|
||||
int c, blk, frags, basesize, sumsize, mapsize, savednrpos = 0;
|
||||
int inomapsize, blkmapsize, astart, aend, ustart, uend;
|
||||
int inomapsize, blkmapsize;
|
||||
struct fs *fs = &sblock;
|
||||
struct cg *cg = &cgrp;
|
||||
ufs_daddr_t dbase, dmax;
|
||||
ufs_daddr_t d;
|
||||
long i, j, k, l, m, n;
|
||||
ufs_daddr_t dbase, dmax, d;
|
||||
int i, j, excessdirs;
|
||||
struct csum *cs;
|
||||
struct csum cstotal;
|
||||
struct inodesc idesc[3];
|
||||
@ -92,7 +95,7 @@ pass5()
|
||||
i = fs->fs_contigsumsize;
|
||||
fs->fs_contigsumsize =
|
||||
MIN(fs->fs_maxcontig, FS_MAXCONTIG);
|
||||
if (CGSIZE(fs) > fs->fs_bsize) {
|
||||
if (CGSIZE(fs) > (u_int)fs->fs_bsize) {
|
||||
pwarn("CANNOT %s CLUSTER MAPS\n", doit);
|
||||
fs->fs_contigsumsize = i;
|
||||
} else if (preen ||
|
||||
@ -232,14 +235,14 @@ pass5()
|
||||
break;
|
||||
|
||||
default:
|
||||
if (j < ROOTINO)
|
||||
if (j < (int)ROOTINO)
|
||||
break;
|
||||
errx(EEXIT, "BAD STATE %d FOR INODE I=%ld",
|
||||
inoinfo(j)->ino_state, j);
|
||||
}
|
||||
}
|
||||
if (c == 0)
|
||||
for (i = 0; i < ROOTINO; i++) {
|
||||
for (i = 0; i < (int)ROOTINO; i++) {
|
||||
setbit(cg_inosused(newcg), i);
|
||||
newcg->cg_cs.cs_nifree--;
|
||||
}
|
||||
@ -301,7 +304,8 @@ pass5()
|
||||
cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
|
||||
cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
|
||||
cs = &fs->fs_cs(fs, c);
|
||||
if (memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 &&
|
||||
if (cursnapshot == 0 &&
|
||||
memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 &&
|
||||
dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
memmove(cs, &newcg->cg_cs, sizeof *cs);
|
||||
sbdirty();
|
||||
@ -311,7 +315,8 @@ pass5()
|
||||
cgdirty();
|
||||
continue;
|
||||
}
|
||||
if ((memcmp(newcg, cg, basesize) != 0 ||
|
||||
if (cursnapshot == 0 &&
|
||||
(memcmp(newcg, cg, basesize) != 0 ||
|
||||
memcmp(&cg_blktot(newcg)[0],
|
||||
&cg_blktot(cg)[0], sumsize) != 0) &&
|
||||
dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
|
||||
@ -320,101 +325,25 @@ pass5()
|
||||
&cg_blktot(newcg)[0], (size_t)sumsize);
|
||||
cgdirty();
|
||||
}
|
||||
if (debug) {
|
||||
for (i = 0; i < inomapsize; i++) {
|
||||
j = cg_inosused(newcg)[i];
|
||||
k = cg_inosused(cg)[i];
|
||||
if (j == k)
|
||||
continue;
|
||||
for (m = 0, l = 1; m < NBBY; m++, l <<= 1) {
|
||||
if ((j & l) == (k & l))
|
||||
continue;
|
||||
n = c * fs->fs_ipg + i * NBBY + m;
|
||||
if ((j & l) != 0)
|
||||
pwarn("%s INODE %d MARKED %s\n",
|
||||
"ALLOCATED", n, "FREE");
|
||||
else
|
||||
pwarn("%s INODE %d MARKED %s\n",
|
||||
"UNALLOCATED", n, "USED");
|
||||
}
|
||||
if (bkgrdflag != 0 || usedsoftdep || debug) {
|
||||
excessdirs = cg->cg_cs.cs_ndir - newcg->cg_cs.cs_ndir;
|
||||
if (excessdirs < 0) {
|
||||
pfatal("LOST %d DIRECTORIES\n", -excessdirs);
|
||||
excessdirs = 0;
|
||||
}
|
||||
astart = ustart = -1;
|
||||
for (i = 0; i < blkmapsize; i++) {
|
||||
j = cg_blksfree(cg)[i];
|
||||
k = cg_blksfree(newcg)[i];
|
||||
if (j == k)
|
||||
continue;
|
||||
for (m = 0, l = 1; m < NBBY; m++, l <<= 1) {
|
||||
if ((j & l) == (k & l))
|
||||
continue;
|
||||
n = c * fs->fs_fpg + i * NBBY + m;
|
||||
if ((j & l) != 0) {
|
||||
if (astart == -1) {
|
||||
astart = aend = n;
|
||||
continue;
|
||||
}
|
||||
if (aend + 1 == n) {
|
||||
aend = n;
|
||||
continue;
|
||||
}
|
||||
pwarn("%s FRAGS %d-%d %s\n",
|
||||
"ALLOCATED", astart, aend,
|
||||
"MARKED FREE");
|
||||
astart = aend = n;
|
||||
} else {
|
||||
if (ustart == -1) {
|
||||
ustart = uend = n;
|
||||
continue;
|
||||
}
|
||||
if (uend + 1 == n) {
|
||||
uend = n;
|
||||
continue;
|
||||
}
|
||||
pwarn("%s FRAGS %d-%d %s\n",
|
||||
"UNALLOCATED", ustart, uend,
|
||||
"MARKED USED");
|
||||
ustart = uend = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (astart != -1)
|
||||
pwarn("%s FRAGS %d-%d %s\n",
|
||||
"ALLOCATED", astart, aend,
|
||||
"MARKED FREE");
|
||||
if (ustart != -1)
|
||||
pwarn("%s FRAGS %d-%d %s\n",
|
||||
"UNALLOCATED", ustart, uend,
|
||||
"MARKED USED");
|
||||
if (excessdirs > 0)
|
||||
check_maps(cg_inosused(newcg), cg_inosused(cg),
|
||||
inomapsize, cg->cg_cgx * fs->fs_ipg, "DIR",
|
||||
freedirs, 0, excessdirs);
|
||||
check_maps(cg_inosused(newcg), cg_inosused(cg),
|
||||
inomapsize, cg->cg_cgx * fs->fs_ipg, "FILE",
|
||||
freefiles, excessdirs, fs->fs_ipg);
|
||||
check_maps(cg_blksfree(cg), cg_blksfree(newcg),
|
||||
blkmapsize, cg->cg_cgx * fs->fs_fpg, "FRAG",
|
||||
freeblks, 0, fs->fs_fpg);
|
||||
}
|
||||
if (usedsoftdep) {
|
||||
for (i = 0; i < inomapsize; i++) {
|
||||
j = cg_inosused(newcg)[i];
|
||||
if ((cg_inosused(cg)[i] & j) == j)
|
||||
continue;
|
||||
for (k = 0; k < NBBY; k++) {
|
||||
if ((j & (1 << k)) == 0)
|
||||
continue;
|
||||
if (cg_inosused(cg)[i] & (1 << k))
|
||||
continue;
|
||||
pwarn("ALLOCATED INODE %d MARKED FREE\n",
|
||||
c * fs->fs_ipg + i * NBBY + k);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < blkmapsize; i++) {
|
||||
j = cg_blksfree(cg)[i];
|
||||
if ((cg_blksfree(newcg)[i] & j) == j)
|
||||
continue;
|
||||
for (k = 0; k < NBBY; k++) {
|
||||
if ((j & (1 << k)) == 0)
|
||||
continue;
|
||||
if (cg_blksfree(newcg)[i] & (1 << k))
|
||||
continue;
|
||||
pwarn("ALLOCATED FRAG %d MARKED FREE\n",
|
||||
c * fs->fs_fpg + i * NBBY + k);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (memcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 &&
|
||||
if (cursnapshot == 0 &&
|
||||
memcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 &&
|
||||
dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
|
||||
memmove(cg_inosused(cg), cg_inosused(newcg),
|
||||
(size_t)mapsize);
|
||||
@ -423,7 +352,8 @@ pass5()
|
||||
}
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
fs->fs_nrpos = savednrpos;
|
||||
if (memcmp(&cstotal, &fs->fs_cstotal, sizeof *cs) != 0
|
||||
if (cursnapshot == 0 &&
|
||||
memcmp(&cstotal, &fs->fs_cstotal, sizeof *cs) != 0
|
||||
&& dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
memmove(&fs->fs_cstotal, &cstotal, sizeof *cs);
|
||||
fs->fs_ronly = 0;
|
||||
@ -431,3 +361,127 @@ pass5()
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_maps(map1, map2, mapsize, startvalue, name, opcode, skip, limit)
|
||||
u_char *map1; /* map of claimed allocations */
|
||||
u_char *map2; /* map of determined allocations */
|
||||
int mapsize; /* size of above two maps */
|
||||
int startvalue; /* resource value for first element in map */
|
||||
char *name; /* name of resource found in maps */
|
||||
int *opcode; /* sysctl opcode to free resource */
|
||||
int skip; /* number of entries to skip before starting to free */
|
||||
int limit; /* limit on number of entries to free */
|
||||
{
|
||||
# define BUFSIZE 16
|
||||
char buf[BUFSIZE];
|
||||
long i, j, k, l, m, n, size;
|
||||
int astart, aend, ustart, uend;
|
||||
|
||||
astart = ustart = aend = uend = -1;
|
||||
for (i = 0; i < mapsize; i++) {
|
||||
j = *map1++;
|
||||
k = *map2++;
|
||||
if (j == k)
|
||||
continue;
|
||||
for (m = 0, l = 1; m < NBBY; m++, l <<= 1) {
|
||||
if ((j & l) == (k & l))
|
||||
continue;
|
||||
n = startvalue + i * NBBY + m;
|
||||
if ((j & l) != 0) {
|
||||
if (astart == -1) {
|
||||
astart = aend = n;
|
||||
continue;
|
||||
}
|
||||
if (aend + 1 == n) {
|
||||
aend = n;
|
||||
continue;
|
||||
}
|
||||
if (astart == aend)
|
||||
pfatal("ALLOCATED %s %d MARKED FREE\n",
|
||||
name, astart);
|
||||
else
|
||||
pfatal("%s %sS %d-%d MARKED FREE\n",
|
||||
"ALLOCATED", name, astart, aend);
|
||||
astart = aend = n;
|
||||
} else {
|
||||
if (ustart == -1) {
|
||||
ustart = uend = n;
|
||||
continue;
|
||||
}
|
||||
if (uend + 1 == n) {
|
||||
uend = n;
|
||||
continue;
|
||||
}
|
||||
size = uend - ustart + 1;
|
||||
if (size <= skip) {
|
||||
skip -= size;
|
||||
ustart = uend = n;
|
||||
continue;
|
||||
}
|
||||
if (skip > 0) {
|
||||
ustart += skip;
|
||||
size -= skip;
|
||||
skip = 0;
|
||||
}
|
||||
if (size > limit)
|
||||
size = limit;
|
||||
if (debug && size == 1)
|
||||
pwarn("%s %s %d MARKED USED\n",
|
||||
"UNALLOCATED", name, ustart);
|
||||
else if (debug)
|
||||
pwarn("%s %sS %d-%d MARKED USED\n",
|
||||
"UNALLOCATED", name, ustart,
|
||||
ustart + size - 1);
|
||||
if (bkgrdflag != 0) {
|
||||
cmd.value = ustart;
|
||||
cmd.size = size;
|
||||
if (sysctl(opcode, MIBSIZE, 0, 0,
|
||||
&cmd, sizeof cmd) == -1) {
|
||||
snprintf(buf, BUFSIZE,
|
||||
"FREE %s", name);
|
||||
rwerror(buf, cmd.value);
|
||||
}
|
||||
}
|
||||
limit -= size;
|
||||
if (limit <= 0)
|
||||
return;
|
||||
ustart = uend = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (astart != -1)
|
||||
if (astart == aend)
|
||||
pfatal("ALLOCATED %s %d MARKED FREE\n", name, astart);
|
||||
else
|
||||
pfatal("ALLOCATED %sS %d-%d MARKED FREE\n",
|
||||
name, astart, aend);
|
||||
if (ustart != -1) {
|
||||
size = uend - ustart + 1;
|
||||
if (size <= skip)
|
||||
return;
|
||||
if (skip > 0) {
|
||||
ustart += skip;
|
||||
size -= skip;
|
||||
}
|
||||
if (size > limit)
|
||||
size = limit;
|
||||
if (debug) {
|
||||
if (size == 1)
|
||||
pwarn("UNALLOCATED %s %d MARKED USED\n",
|
||||
name, ustart);
|
||||
else
|
||||
pwarn("UNALLOCATED %sS %d-%d MARKED USED\n",
|
||||
name, ustart, ustart + size - 1);
|
||||
}
|
||||
if (bkgrdflag != 0) {
|
||||
cmd.value = ustart;
|
||||
cmd.size = size;
|
||||
if (sysctl(opcode, MIBSIZE, 0, 0, &cmd,
|
||||
sizeof cmd) == -1) {
|
||||
snprintf(buf, BUFSIZE, "FREE %s", name);
|
||||
rwerror(buf, cmd.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ static const char rcsid[] =
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
@ -86,25 +86,73 @@ setup(dev)
|
||||
skipclean = fflag ? 0 : preen;
|
||||
if (stat(dev, &statb) < 0) {
|
||||
printf("Can't stat %s: %s\n", dev, strerror(errno));
|
||||
if (bkgrdflag) {
|
||||
unlink(snapname);
|
||||
bkgrdflag = 0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if ((statb.st_mode & S_IFMT) != S_IFCHR &&
|
||||
(statb.st_mode & S_IFMT) != S_IFBLK) {
|
||||
if ((statb.st_flags & SF_SNAPSHOT) != 0) {
|
||||
if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) {
|
||||
unlink(snapname);
|
||||
printf("background fsck lacks a snapshot\n");
|
||||
exit(EEXIT);
|
||||
}
|
||||
if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) {
|
||||
cursnapshot = statb.st_ino;
|
||||
} else {
|
||||
pfatal("%s is not a disk device", dev);
|
||||
if (reply("CONTINUE") == 0)
|
||||
return (0);
|
||||
if (cvtlevel == 0 ||
|
||||
(statb.st_flags & SF_SNAPSHOT) == 0) {
|
||||
if (preen && bkgrdflag) {
|
||||
unlink(snapname);
|
||||
bkgrdflag = 0;
|
||||
}
|
||||
pfatal("%s is not a disk device", dev);
|
||||
if (reply("CONTINUE") == 0) {
|
||||
if (bkgrdflag) {
|
||||
unlink(snapname);
|
||||
bkgrdflag = 0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
if (bkgrdflag) {
|
||||
unlink(snapname);
|
||||
bkgrdflag = 0;
|
||||
}
|
||||
pfatal("cannot convert a snapshot");
|
||||
exit(EEXIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
|
||||
if (bkgrdflag) {
|
||||
unlink(snapname);
|
||||
bkgrdflag = 0;
|
||||
}
|
||||
printf("Can't open %s: %s\n", dev, strerror(errno));
|
||||
return (0);
|
||||
}
|
||||
if (bkgrdflag) {
|
||||
unlink(snapname);
|
||||
size = MIBSIZE;
|
||||
if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0||
|
||||
sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0||
|
||||
sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0||
|
||||
sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 ||
|
||||
sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) {
|
||||
pfatal("kernel lacks background fsck support\n");
|
||||
exit(EEXIT);
|
||||
}
|
||||
cmd.version = FFS_CMD_VERSION;
|
||||
cmd.handle = fsreadfd;
|
||||
fswritefd = -1;
|
||||
}
|
||||
if (preen == 0)
|
||||
printf("** %s", dev);
|
||||
if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
|
||||
if (bkgrdflag == 0 &&
|
||||
(nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) {
|
||||
fswritefd = -1;
|
||||
if (preen)
|
||||
pfatal("NO WRITE ACCESS");
|
||||
@ -178,7 +226,7 @@ setup(dev)
|
||||
}
|
||||
if (sblock.fs_interleave < 1 ||
|
||||
sblock.fs_interleave > sblock.fs_nsect) {
|
||||
pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
|
||||
pfatal("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
|
||||
sblock.fs_interleave);
|
||||
sblock.fs_interleave = 1;
|
||||
if (preen)
|
||||
@ -190,7 +238,7 @@ setup(dev)
|
||||
}
|
||||
if (sblock.fs_npsect < sblock.fs_nsect ||
|
||||
sblock.fs_npsect > sblock.fs_nsect*2) {
|
||||
pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
|
||||
pfatal("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
|
||||
sblock.fs_npsect);
|
||||
sblock.fs_npsect = sblock.fs_nsect;
|
||||
if (preen)
|
||||
|
@ -44,6 +44,7 @@ static const char rcsid[] =
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
Loading…
Reference in New Issue
Block a user