aboutsummaryrefslogtreecommitdiff
path: root/sbin/fsck_ffs/gjournal.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/fsck_ffs/gjournal.c')
-rw-r--r--sbin/fsck_ffs/gjournal.c411
1 files changed, 38 insertions, 373 deletions
diff --git a/sbin/fsck_ffs/gjournal.c b/sbin/fsck_ffs/gjournal.c
index 6e3dbd2da41e..b65589b5bd08 100644
--- a/sbin/fsck_ffs/gjournal.c
+++ b/sbin/fsck_ffs/gjournal.c
@@ -56,354 +56,30 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/param.h>
-#include <sys/disklabel.h>
-#include <sys/mount.h>
+#include <string.h>
#include <sys/stat.h>
-
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <libufs.h>
-#include <strings.h>
-#include <err.h>
-#include <assert.h>
-
#include "fsck.h"
-struct cgchain {
- union {
- struct cg cgcu_cg;
- char cgcu_buf[MAXBSIZE];
- } cgc_union;
- int cgc_busy;
- int cgc_dirty;
- LIST_ENTRY(cgchain) cgc_next;
-};
-#define cgc_cg cgc_union.cgcu_cg
-
-#define MAX_CACHED_CGS 1024
-static unsigned ncgs = 0;
-static LIST_HEAD(, cgchain) cglist = LIST_HEAD_INITIALIZER(cglist);
-
-static const char *devnam;
-static struct uufsd *diskp = NULL;
-static struct fs *fs = NULL;
-
-static void putcgs(void);
-
-/*
- * Return cylinder group from the cache or load it if it is not in the
- * cache yet.
- * Don't cache more than MAX_CACHED_CGS cylinder groups.
- */
-static struct cgchain *
-getcg(int cg)
-{
- struct cgchain *cgc;
-
- assert(diskp != NULL && fs != NULL);
- LIST_FOREACH(cgc, &cglist, cgc_next) {
- if (cgc->cgc_cg.cg_cgx == cg) {
- //printf("%s: Found cg=%d\n", __func__, cg);
- return (cgc);
- }
- }
- /*
- * Our cache is full? Let's clean it up.
- */
- if (ncgs >= MAX_CACHED_CGS) {
- //printf("%s: Flushing CGs.\n", __func__);
- putcgs();
- }
- cgc = malloc(sizeof(*cgc));
- if (cgc == NULL) {
- /*
- * Cannot allocate memory?
- * Let's put all currently loaded and not busy cylinder groups
- * on disk and try again.
- */
- //printf("%s: No memory, flushing CGs.\n", __func__);
- putcgs();
- cgc = malloc(sizeof(*cgc));
- if (cgc == NULL)
- err(1, "malloc(%zu)", sizeof(*cgc));
- }
- if (cgget(fsreadfd, fs, cg, &cgc->cgc_cg) == -1)
- err(1, "cgget(%d)", cg);
- cgc->cgc_busy = 0;
- cgc->cgc_dirty = 0;
- LIST_INSERT_HEAD(&cglist, cgc, cgc_next);
- ncgs++;
- //printf("%s: Read cg=%d\n", __func__, cg);
- return (cgc);
-}
-
-/*
- * Mark cylinder group as dirty - it will be written back on putcgs().
- */
-static void
-dirtycg(struct cgchain *cgc)
-{
-
- cgc->cgc_dirty = 1;
-}
-
-/*
- * Mark cylinder group as busy - it will not be freed on putcgs().
- */
-static void
-busycg(struct cgchain *cgc)
-{
-
- cgc->cgc_busy = 1;
-}
-
-/*
- * Unmark the given cylinder group as busy.
- */
-static void
-unbusycg(struct cgchain *cgc)
-{
-
- cgc->cgc_busy = 0;
-}
-
-/*
- * Write back all dirty cylinder groups.
- * Free all non-busy cylinder groups.
- */
-static void
-putcgs(void)
-{
- struct cgchain *cgc, *cgc2;
-
- assert(diskp != NULL && fs != NULL);
- LIST_FOREACH_SAFE(cgc, &cglist, cgc_next, cgc2) {
- if (cgc->cgc_busy)
- continue;
- LIST_REMOVE(cgc, cgc_next);
- ncgs--;
- if (cgc->cgc_dirty) {
- if (cgput(fswritefd, fs, &cgc->cgc_cg) == -1)
- err(1, "cgput(%d)", cgc->cgc_cg.cg_cgx);
- //printf("%s: Wrote cg=%d\n", __func__,
- // cgc->cgc_cg.cg_cgx);
- }
- free(cgc);
- }
-}
-
-#if 0
-/*
- * Free all non-busy cylinder groups without storing the dirty ones.
- */
-static void
-cancelcgs(void)
-{
- struct cgchain *cgc;
-
- assert(diskp != NULL && fs != NULL);
- while ((cgc = LIST_FIRST(&cglist)) != NULL) {
- if (cgc->cgc_busy)
- continue;
- LIST_REMOVE(cgc, cgc_next);
- //printf("%s: Canceled cg=%d\n", __func__, cgc->cgc_cg.cg_cgx);
- free(cgc);
- }
-}
-#endif
-
-/*
- * Open the given provider, load superblock.
- */
-static void
-opendisk(void)
-{
- if (diskp != NULL)
- return;
- diskp = &disk;
- if (ufs_disk_fillout(diskp, devnam) == -1) {
- err(1, "ufs_disk_fillout(%s) failed: %s", devnam,
- diskp->d_error);
- }
- fs = &diskp->d_fs;
-}
-
-/*
- * Mark file system as clean, write the super-block back, close the disk.
- */
-static void
-closedisk(void)
-{
-
- fs->fs_clean = 1;
- if (sbwrite(diskp, 0) == -1)
- err(1, "sbwrite(%s)", devnam);
- if (ufs_disk_close(diskp) == -1)
- err(1, "ufs_disk_close(%s)", devnam);
- free(diskp);
- diskp = NULL;
- fs = NULL;
-}
-
-static void
-blkfree(ufs2_daddr_t bno, long size)
-{
- struct cgchain *cgc;
- struct cg *cgp;
- ufs1_daddr_t fragno, cgbno;
- int i, cg, blk, frags, bbase;
- u_int8_t *blksfree;
-
- cg = dtog(fs, bno);
- cgc = getcg(cg);
- dirtycg(cgc);
- cgp = &cgc->cgc_cg;
- cgbno = dtogd(fs, bno);
- blksfree = cg_blksfree(cgp);
- if (size == fs->fs_bsize) {
- fragno = fragstoblks(fs, cgbno);
- if (!ffs_isfreeblock(fs, blksfree, fragno))
- assert(!"blkfree: freeing free block");
- ffs_setblock(fs, blksfree, fragno);
- ffs_clusteracct(fs, cgp, fragno, 1);
- cgp->cg_cs.cs_nbfree++;
- fs->fs_cstotal.cs_nbfree++;
- fs->fs_cs(fs, cg).cs_nbfree++;
- } else {
- bbase = cgbno - fragnum(fs, cgbno);
- /*
- * decrement the counts associated with the old frags
- */
- blk = blkmap(fs, blksfree, bbase);
- ffs_fragacct(fs, blk, cgp->cg_frsum, -1);
- /*
- * deallocate the fragment
- */
- frags = numfrags(fs, size);
- for (i = 0; i < frags; i++) {
- if (isset(blksfree, cgbno + i))
- assert(!"blkfree: freeing free frag");
- setbit(blksfree, cgbno + i);
- }
- cgp->cg_cs.cs_nffree += i;
- fs->fs_cstotal.cs_nffree += i;
- fs->fs_cs(fs, cg).cs_nffree += i;
- /*
- * add back in counts associated with the new frags
- */
- blk = blkmap(fs, blksfree, bbase);
- ffs_fragacct(fs, blk, cgp->cg_frsum, 1);
- /*
- * if a complete block has been reassembled, account for it
- */
- fragno = fragstoblks(fs, bbase);
- if (ffs_isblock(fs, blksfree, fragno)) {
- cgp->cg_cs.cs_nffree -= fs->fs_frag;
- fs->fs_cstotal.cs_nffree -= fs->fs_frag;
- fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
- ffs_clusteracct(fs, cgp, fragno, 1);
- cgp->cg_cs.cs_nbfree++;
- fs->fs_cstotal.cs_nbfree++;
- fs->fs_cs(fs, cg).cs_nbfree++;
- }
- }
-}
-
-/*
- * Recursively free all indirect blocks.
- */
-static void
-freeindir(ufs2_daddr_t blk, int level)
-{
- char sblks[MAXBSIZE];
- ufs2_daddr_t *blks;
- int i;
-
- if (bread(diskp, fsbtodb(fs, blk), (void *)&sblks, (size_t)fs->fs_bsize) == -1)
- err(1, "bread: %s", diskp->d_error);
- blks = (ufs2_daddr_t *)&sblks;
- for (i = 0; i < NINDIR(fs); i++) {
- if (blks[i] == 0)
- break;
- if (level == 0)
- blkfree(blks[i], fs->fs_bsize);
- else
- freeindir(blks[i], level - 1);
- }
- blkfree(blk, fs->fs_bsize);
-}
-
-#define dblksize(fs, dino, lbn) \
- ((dino)->di_size >= smalllblktosize(fs, (lbn) + 1) \
- ? (fs)->fs_bsize \
- : fragroundup(fs, blkoff(fs, (dino)->di_size)))
-
-/*
- * Free all blocks associated with the given inode.
- */
-static void
-clear_inode(struct ufs2_dinode *dino)
-{
- ufs2_daddr_t bn;
- int extblocks, i, level;
- off_t osize;
- long bsize;
-
- extblocks = 0;
- if (fs->fs_magic == FS_UFS2_MAGIC && dino->di_extsize > 0)
- extblocks = btodb(fragroundup(fs, dino->di_extsize));
- /* deallocate external attributes blocks */
- if (extblocks > 0) {
- osize = dino->di_extsize;
- dino->di_blocks -= extblocks;
- dino->di_extsize = 0;
- for (i = 0; i < UFS_NXADDR; i++) {
- if (dino->di_extb[i] == 0)
- continue;
- blkfree(dino->di_extb[i], sblksize(fs, osize, i));
- }
- }
-#define SINGLE 0 /* index of single indirect block */
-#define DOUBLE 1 /* index of double indirect block */
-#define TRIPLE 2 /* index of triple indirect block */
- /* deallocate indirect blocks */
- for (level = SINGLE; level <= TRIPLE; level++) {
- if (dino->di_ib[level] == 0)
- break;
- freeindir(dino->di_ib[level], level);
- }
- /* deallocate direct blocks and fragments */
- for (i = 0; i < UFS_NDADDR; i++) {
- bn = dino->di_db[i];
- if (bn == 0)
- continue;
- bsize = dblksize(fs, dino, i);
- blkfree(bn, bsize);
- }
-}
-
void
gjournal_check(const char *filesys)
{
- union dinodep dp;
- struct cgchain *cgc;
+ struct fs *fs;
+ struct inode ip;
+ union dinode *dp;
+ struct bufarea *cgbp;
struct cg *cgp;
+ struct inodesc idesc;
uint8_t *inosused;
ino_t cino, ino;
int cg;
- devnam = filesys;
- opendisk();
+ fs = &sblock;
/* Are there any unreferenced inodes in this file system? */
if (fs->fs_unrefs == 0) {
//printf("No unreferenced inodes.\n");
- closedisk();
+ sbdirty();
+ ckfini(1);
return;
}
@@ -419,77 +95,67 @@ gjournal_check(const char *filesys)
cg * 100 / fs->fs_ncg);
got_sigalarm = 0;
}
- cgc = getcg(cg);
- cgp = &cgc->cgc_cg;
+ cgbp = cglookup(cg);
+ cgp = cgbp->b_un.b_cg;
+ if (!check_cgmagic(cg, cgbp, 0)) {
+ rerun = 1;
+ ckfini(0);
+ return;
+ }
/* Are there any unreferenced inodes in this cylinder group? */
if (cgp->cg_unrefs == 0)
continue;
//printf("Analizing cylinder group %d (count=%d)\n", cg, cgp->cg_unrefs);
/*
- * We are going to modify this cylinder group, so we want it to
- * be written back.
- */
- dirtycg(cgc);
- /* We don't want it to be freed in the meantime. */
- busycg(cgc);
- inosused = cg_inosused(cgp);
- /*
* Now go through the list of all inodes in this cylinder group
* to find unreferenced ones.
*/
+ inosused = cg_inosused(cgp);
for (cino = 0; cino < fs->fs_ipg; cino++) {
ino = fs->fs_ipg * cg + cino;
/* Unallocated? Skip it. */
if (isclr(inosused, cino))
continue;
- if (getinode(diskp, &dp, ino) == -1)
- err(1, "getinode (cg=%d ino=%ju) %s",
- cg, (uintmax_t)ino, diskp->d_error);
+ ginode(ino, &ip);
+ dp = ip.i_dp;
/* Not a regular file nor directory? Skip it. */
- if (!S_ISREG(dp.dp2->di_mode) &&
- !S_ISDIR(dp.dp2->di_mode))
+ if (!S_ISREG(dp->dp2.di_mode) &&
+ !S_ISDIR(dp->dp2.di_mode)) {
+ irelse(&ip);
continue;
+ }
/* Has reference(s)? Skip it. */
- if (dp.dp2->di_nlink > 0)
+ if (dp->dp2.di_nlink > 0) {
+ irelse(&ip);
continue;
+ }
/* printf("Clearing inode=%d (size=%jd)\n", ino,
- (intmax_t)dp.dp2->di_size); */
- /* Free inode's blocks. */
- clear_inode(dp.dp2);
+ (intmax_t)dp->dp2->di_size); */
/* Deallocate it. */
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = ADDR;
+ idesc.id_func = freeblock;
+ idesc.id_number = ino;
+ clri(&idesc, "UNREF", 1);
clrbit(inosused, cino);
/* Update position of last used inode. */
if (ino < cgp->cg_irotor)
cgp->cg_irotor = ino;
/* Update statistics. */
- cgp->cg_cs.cs_nifree++;
- fs->fs_cs(fs, cg).cs_nifree++;
- fs->fs_cstotal.cs_nifree++;
cgp->cg_unrefs--;
fs->fs_unrefs--;
- /* If this is directory, update related statistics. */
- if (S_ISDIR(dp.dp2->di_mode)) {
- cgp->cg_cs.cs_ndir--;
- fs->fs_cs(fs, cg).cs_ndir--;
- fs->fs_cstotal.cs_ndir--;
- }
/* Zero-fill the inode. */
- *dp.dp2 = ufs2_zino;
+ dp->dp2 = zino.dp2;
/* Write the inode back. */
- if (putinode(diskp) == -1)
- err(1, "putinode (cg=%d ino=%ju) %s",
- cg, (uintmax_t)ino, diskp->d_error);
+ inodirty(&ip);
+ irelse(&ip);
+ cgdirty(cgbp);
if (cgp->cg_unrefs == 0) {
//printf("No more unreferenced inodes in cg=%d.\n", cg);
break;
}
}
/*
- * We don't need this cylinder group anymore, so feel free to
- * free it if needed.
- */
- unbusycg(cgc);
- /*
* If there are no more unreferenced inodes, there is no need to
* check other cylinder groups.
*/
@@ -499,8 +165,7 @@ gjournal_check(const char *filesys)
break;
}
}
- /* Write back modified cylinder groups. */
- putcgs();
/* Write back updated statistics and super-block. */
- closedisk();
+ sbdirty();
+ ckfini(1);
}