summaryrefslogtreecommitdiffstats
path: root/sbin/fsck_ifs
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/fsck_ifs')
-rw-r--r--sbin/fsck_ifs/dir.c14
-rw-r--r--sbin/fsck_ifs/fsck.h7
-rw-r--r--sbin/fsck_ifs/inode.c11
-rw-r--r--sbin/fsck_ifs/pass1.c21
-rw-r--r--sbin/fsck_ifs/pass5.c70
-rw-r--r--sbin/fsck_ifs/setup.c13
6 files changed, 121 insertions, 15 deletions
diff --git a/sbin/fsck_ifs/dir.c b/sbin/fsck_ifs/dir.c
index f5fb6a0..5ce99f6 100644
--- a/sbin/fsck_ifs/dir.c
+++ b/sbin/fsck_ifs/dir.c
@@ -241,7 +241,7 @@ dircheck(idesc, dp)
if (dp->d_reclen == 0 ||
dp->d_reclen > spaceleft ||
(dp->d_reclen & 0x3) != 0)
- return (0);
+ goto bad;
if (dp->d_ino == 0)
return (1);
size = DIRSIZ(!newinofmt, dp);
@@ -261,13 +261,19 @@ dircheck(idesc, dp)
idesc->id_filesize < size ||
namlen > MAXNAMLEN ||
type > 15)
- return (0);
+ goto bad;
for (cp = dp->d_name, size = 0; size < namlen; size++)
if (*cp == '\0' || (*cp++ == '/'))
- return (0);
+ goto bad;
if (*cp != '\0')
- return (0);
+ goto bad;
return (1);
+bad:
+ if (debug)
+ printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n",
+ dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type,
+ dp->d_name);
+ return (0);
}
void
diff --git a/sbin/fsck_ifs/fsck.h b/sbin/fsck_ifs/fsck.h
index 9d59c8f..f0280fe 100644
--- a/sbin/fsck_ifs/fsck.h
+++ b/sbin/fsck_ifs/fsck.h
@@ -114,12 +114,14 @@ struct bufarea *pbp; /* current inode block */
#define cgrp (*cgblk.b_un.b_cg)
enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
+ino_t cursnapshot;
struct inodesc {
enum fixstate id_fix; /* policy on fixing errors */
int (*id_func)(); /* function to be applied to blocks of inode */
ino_t id_number; /* inode number described */
ino_t id_parent; /* for DATA nodes, their parent */
+ int id_lbn; /* logical block number of current block */
ufs_daddr_t id_blkno; /* current block number being examined */
int id_numfrags; /* number of frags contained in block */
quad_t id_filesize; /* for DATA nodes, the size of the directory */
@@ -130,8 +132,9 @@ struct inodesc {
char id_type; /* type of descriptor, DATA or ADDR */
};
/* file types */
-#define DATA 1
-#define ADDR 2
+#define DATA 1 /* a directory */
+#define SNAP 2 /* a snapshot */
+#define ADDR 3 /* anything but a directory or a snapshot */
/*
* Linked list of duplicate blocks.
diff --git a/sbin/fsck_ifs/inode.c b/sbin/fsck_ifs/inode.c
index dbf86f7..e241cdb 100644
--- a/sbin/fsck_ifs/inode.c
+++ b/sbin/fsck_ifs/inode.c
@@ -71,6 +71,7 @@ ckinode(dp, idesc)
if (idesc->id_fix != IGNORE)
idesc->id_fix = DONTKNOW;
+ idesc->id_lbn = -1;
idesc->id_entryno = 0;
idesc->id_filesize = dp->di_size;
mode = dp->di_mode & IFMT;
@@ -80,6 +81,7 @@ ckinode(dp, idesc)
dino = *dp;
ndb = howmany(dino.di_size, sblock.fs_bsize);
for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
+ idesc->id_lbn++;
if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
idesc->id_numfrags =
numfrags(&sblock, fragroundup(&sblock, offset));
@@ -106,7 +108,7 @@ ckinode(dp, idesc)
continue;
}
idesc->id_blkno = *ap;
- if (idesc->id_type == ADDR)
+ if (idesc->id_type != DATA)
ret = (*idesc->id_func)(idesc);
else
ret = dirscan(idesc);
@@ -117,12 +119,14 @@ ckinode(dp, idesc)
remsize = dino.di_size - sblock.fs_bsize * NDADDR;
sizepb = sblock.fs_bsize;
for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
+ sizepb *= NINDIR(&sblock);
if (*ap) {
idesc->id_blkno = *ap;
ret = iblock(idesc, n, remsize);
if (ret & STOP)
return (ret);
} else {
+ idesc->id_lbn += sizepb / sblock.fs_bsize;
if (idesc->id_type == DATA && remsize > 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
@@ -141,7 +145,6 @@ ckinode(dp, idesc)
}
}
}
- sizepb *= NINDIR(&sblock);
remsize -= sizepb;
}
return (KEEPON);
@@ -162,7 +165,7 @@ iblock(idesc, ilevel, isize)
char pathbuf[MAXPATHLEN + 1];
struct dinode *dp;
- if (idesc->id_type == ADDR) {
+ if (idesc->id_type != DATA) {
func = idesc->id_func;
if (((n = (*func)(idesc)) & KEEPON) == 0)
return (n);
@@ -193,6 +196,8 @@ iblock(idesc, ilevel, isize)
}
aplim = &bp->b_un.b_indir[nif];
for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
+ if (ilevel == 0)
+ idesc->id_lbn++;
if (*ap) {
idesc->id_blkno = *ap;
if (ilevel == 0)
diff --git a/sbin/fsck_ifs/pass1.c b/sbin/fsck_ifs/pass1.c
index dd09b00..59826a7 100644
--- a/sbin/fsck_ifs/pass1.c
+++ b/sbin/fsck_ifs/pass1.c
@@ -40,6 +40,7 @@ static const char rcsid[] =
#endif /* not lint */
#include <sys/param.h>
+#include <sys/stat.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
@@ -82,7 +83,6 @@ pass1()
* Find all allocated blocks.
*/
memset(&idesc, 0, sizeof(struct inodesc));
- idesc.id_type = ADDR;
idesc.id_func = pass1check;
n_files = n_blks = 0;
for (c = 0; c < sblock.fs_ncg; c++) {
@@ -306,6 +306,10 @@ checkinode(inumber, idesc)
}
badblk = dupblk = 0;
idesc->id_number = inumber;
+ if (dp->di_flags & SF_SNAPSHOT)
+ idesc->id_type = SNAP;
+ else
+ idesc->id_type = ADDR;
(void)ckinode(dp, idesc);
idesc->id_entryno *= btodb(sblock.fs_fsize);
if (dp->di_blocks != idesc->id_entryno) {
@@ -341,6 +345,21 @@ pass1check(idesc)
register struct dups *dlp;
struct dups *new;
+ if (idesc->id_type == SNAP) {
+ if (blkno == BLK_NOCOPY)
+ return (KEEPON);
+ if (idesc->id_number == cursnapshot) {
+ if (blkno == blkstofrags(&sblock, idesc->id_lbn))
+ return (KEEPON);
+ if (blkno == BLK_SNAP) {
+ blkno = blkstofrags(&sblock, idesc->id_lbn);
+ idesc->id_entryno -= idesc->id_numfrags;
+ }
+ } else {
+ if (blkno == BLK_SNAP)
+ return (KEEPON);
+ }
+ }
if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
blkerror(idesc->id_number, "BAD", blkno);
if (badblk++ >= MAXBAD) {
diff --git a/sbin/fsck_ifs/pass5.c b/sbin/fsck_ifs/pass5.c
index d5edaac..e395625 100644
--- a/sbin/fsck_ifs/pass5.c
+++ b/sbin/fsck_ifs/pass5.c
@@ -53,12 +53,12 @@ void
pass5()
{
int c, blk, frags, basesize, sumsize, mapsize, savednrpos = 0;
- int inomapsize, blkmapsize;
+ int inomapsize, blkmapsize, astart, aend, ustart, uend;
struct fs *fs = &sblock;
struct cg *cg = &cgrp;
ufs_daddr_t dbase, dmax;
ufs_daddr_t d;
- long i, j, k;
+ long i, j, k, l, m, n;
struct csum *cs;
struct csum cstotal;
struct inodesc idesc[3];
@@ -314,6 +314,72 @@ 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");
+ }
+ }
+ 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 (usedsoftdep) {
for (i = 0; i < inomapsize; i++) {
j = cg_inosused(newcg)[i];
diff --git a/sbin/fsck_ifs/setup.c b/sbin/fsck_ifs/setup.c
index 49bbc8d..6c4098c 100644
--- a/sbin/fsck_ifs/setup.c
+++ b/sbin/fsck_ifs/setup.c
@@ -82,6 +82,7 @@ setup(dev)
havesb = 0;
fswritefd = -1;
+ cursnapshot = 0;
skipclean = fflag ? 0 : preen;
if (stat(dev, &statb) < 0) {
printf("Can't stat %s: %s\n", dev, strerror(errno));
@@ -89,9 +90,13 @@ setup(dev)
}
if ((statb.st_mode & S_IFMT) != S_IFCHR &&
(statb.st_mode & S_IFMT) != S_IFBLK) {
- pfatal("%s is not a disk device", dev);
- if (reply("CONTINUE") == 0)
- return (0);
+ if ((statb.st_flags & SF_SNAPSHOT) != 0) {
+ cursnapshot = statb.st_ino;
+ } else {
+ pfatal("%s is not a disk device", dev);
+ if (reply("CONTINUE") == 0)
+ return (0);
+ }
}
if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
printf("Can't open %s: %s\n", dev, strerror(errno));
@@ -378,6 +383,8 @@ readsb(listerr)
memmove(altsblock.fs_csp, sblock.fs_csp, sizeof sblock.fs_csp);
altsblock.fs_maxcluster = sblock.fs_maxcluster;
memmove(altsblock.fs_fsmnt, sblock.fs_fsmnt, sizeof sblock.fs_fsmnt);
+ memmove(altsblock.fs_snapinum, sblock.fs_snapinum,
+ sizeof sblock.fs_snapinum);
memmove(altsblock.fs_sparecon,
sblock.fs_sparecon, sizeof sblock.fs_sparecon);
/*
OpenPOWER on IntegriCloud