diff options
Diffstat (limited to 'sbin/fsck_ffs/gjournal.c')
| -rw-r--r-- | sbin/fsck_ffs/gjournal.c | 411 |
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); } |
