Date: Sat, 24 Apr 2010 07:58:59 +0000 (UTC) From: Pawel Jakub Dawidek <pjd@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r207144 - head/sbin/fsck_ffs Message-ID: <201004240758.o3O7wxZA067332@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: pjd Date: Sat Apr 24 07:58:59 2010 New Revision: 207144 URL: http://svn.freebsd.org/changeset/base/207144 Log: suj.c seems to contain two versions of the code. Remove the one that doesn't compile. Modified: head/sbin/fsck_ffs/suj.c Modified: head/sbin/fsck_ffs/suj.c ============================================================================== --- head/sbin/fsck_ffs/suj.c Sat Apr 24 07:54:49 2010 (r207143) +++ head/sbin/fsck_ffs/suj.c Sat Apr 24 07:58:59 2010 (r207144) @@ -2632,2068 +2632,3 @@ suj_check(const char *filesys) return (0); } -/*- - * Copyright (c) 2009 Jeffrey W. Roberson <jeff@FreeBSD.org> - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/disklabel.h> -#include <sys/mount.h> -#include <sys/stat.h> - -#include <ufs/ufs/ufsmount.h> -#include <ufs/ufs/dinode.h> -#include <ufs/ufs/dir.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" - -static void ino_decr(ino_t); - -#define SUJ_HASHSIZE 128 -#define SUJ_HASHMASK (SUJ_HASHSIZE - 1) -#define SUJ_HASH(x) ((x * 2654435761) & SUJ_HASHMASK) - -struct suj_seg { - TAILQ_ENTRY(suj_seg) ss_next; - struct jsegrec ss_rec; - uint8_t *ss_blk; -}; - -struct suj_rec { - TAILQ_ENTRY(suj_rec) sr_next; - union jrec *sr_rec; -}; -TAILQ_HEAD(srechd, suj_rec); - -struct suj_ino { - LIST_ENTRY(suj_ino) si_next; - struct srechd si_recs; - struct srechd si_movs; - ino_t si_ino; - int si_nlinkadj; - int si_skipparent; - int si_linkadj; - int si_hasrecs; - int si_blkadj; -}; -LIST_HEAD(inohd, suj_ino); - -struct suj_blk { - LIST_ENTRY(suj_blk) sb_next; - struct srechd sb_recs; - ufs2_daddr_t sb_blk; -}; -LIST_HEAD(blkhd, suj_blk); - -struct data_blk { - LIST_ENTRY(data_blk) db_next; - uint8_t *db_buf; - ufs2_daddr_t db_blk; - int db_size; -}; - -struct ino_blk { - LIST_ENTRY(ino_blk) ib_next; - uint8_t *ib_buf; - int ib_dirty; - ufs2_daddr_t ib_blk; -}; -LIST_HEAD(iblkhd, ino_blk); - -struct suj_cg { - LIST_ENTRY(suj_cg) sc_next; - struct blkhd sc_blkhash[SUJ_HASHSIZE]; - struct inohd sc_inohash[SUJ_HASHSIZE]; - struct iblkhd sc_iblkhash[SUJ_HASHSIZE]; - struct ino_blk *sc_lastiblk; - uint8_t *sc_cgbuf; - struct cg *sc_cgp; - int sc_dirty; - int sc_cgx; -}; - -LIST_HEAD(cghd, suj_cg) cghash[SUJ_HASHSIZE]; -LIST_HEAD(dblkhd, data_blk) dbhash[SUJ_HASHSIZE]; - -TAILQ_HEAD(seghd, suj_seg) allsegs; -uint64_t oldseq; -static struct uufsd *disk = NULL; -static struct fs *fs = NULL; - -/* - * Summary statistics. - */ -uint64_t freefrags; -uint64_t freeblocks; -uint64_t freeinos; -uint64_t freedir; -uint64_t jbytes; -uint64_t jrecs; - -typedef void (*ino_visitor)(ino_t, ufs_lbn_t, ufs2_daddr_t, int); - -static void * -errmalloc(size_t n) -{ - void *a; - - a = malloc(n); - if (a == NULL) - errx(1, "malloc(%zu)", n); - return (a); -} - -/* - * Open the given provider, load superblock. - */ -static void -opendisk(const char *devnam) -{ - if (disk != NULL) - return; - disk = malloc(sizeof(*disk)); - if (disk == NULL) - errx(1, "malloc(%zu)", sizeof(*disk)); - if (ufs_disk_fillout(disk, devnam) == -1) { - err(1, "ufs_disk_fillout(%s) failed: %s", devnam, - disk->d_error); - } - fs = &disk->d_fs; - /* - * Setup a few things so reply() can work. - */ - bcopy(fs, &sblock, sizeof(sblock)); - fsreadfd = disk->d_fd; - fswritefd = disk->d_fd; -} - -/* - * Mark file system as clean, write the super-block back, close the disk. - */ -static void -closedisk(const char *devnam) -{ - struct csum *cgsum; - int i; - - /* - * Recompute the fs summary info from correct cs summaries. - */ - bzero(&fs->fs_cstotal, sizeof(struct csum_total)); - for (i = 0; i < fs->fs_ncg; i++) { - cgsum = &fs->fs_cs(fs, i); - fs->fs_cstotal.cs_nffree += cgsum->cs_nffree; - fs->fs_cstotal.cs_nbfree += cgsum->cs_nbfree; - fs->fs_cstotal.cs_nifree += cgsum->cs_nifree; - fs->fs_cstotal.cs_ndir += cgsum->cs_ndir; - } - /* XXX Don't set clean for now, we don't trust the journal. */ - /* fs->fs_clean = 1; */ - fs->fs_time = time(NULL); - fs->fs_mtime = time(NULL); - if (sbwrite(disk, 0) == -1) - err(1, "sbwrite(%s)", devnam); - if (ufs_disk_close(disk) == -1) - err(1, "ufs_disk_close(%s)", devnam); - free(disk); - disk = NULL; - fs = NULL; - fsreadfd = -1; - fswritefd = -1; -} - -/* - * Lookup a cg by number in the hash so we can keep track of which cgs - * need stats rebuilt. - */ -static struct suj_cg * -cg_lookup(int cgx) -{ - struct cghd *hd; - struct suj_cg *sc; - - if (cgx < 0 || cgx >= fs->fs_ncg) { - abort(); - errx(1, "Bad cg number %d", cgx); - } - hd = &cghash[SUJ_HASH(cgx)]; - LIST_FOREACH(sc, hd, sc_next) - if (sc->sc_cgx == cgx) - return (sc); - sc = errmalloc(sizeof(*sc)); - bzero(sc, sizeof(*sc)); - sc->sc_cgbuf = errmalloc(fs->fs_bsize); - sc->sc_cgp = (struct cg *)sc->sc_cgbuf; - sc->sc_cgx = cgx; - LIST_INSERT_HEAD(hd, sc, sc_next); - if (bread(disk, fsbtodb(fs, cgtod(fs, sc->sc_cgx)), sc->sc_cgbuf, - fs->fs_bsize) == -1) - err(1, "Unable to read cylinder group %d", sc->sc_cgx); - - return (sc); -} - -/* - * Lookup an inode number in the hash and allocate a suj_ino if it does - * not exist. - */ -static struct suj_ino * -ino_lookup(ino_t ino, int creat) -{ - struct suj_ino *sino; - struct inohd *hd; - struct suj_cg *sc; - - sc = cg_lookup(ino_to_cg(fs, ino)); - hd = &sc->sc_inohash[SUJ_HASH(ino)]; - LIST_FOREACH(sino, hd, si_next) - if (sino->si_ino == ino) - return (sino); - if (creat == 0) - return (NULL); - sino = errmalloc(sizeof(*sino)); - bzero(sino, sizeof(*sino)); - sino->si_ino = ino; - sino->si_nlinkadj = 0; - TAILQ_INIT(&sino->si_recs); - TAILQ_INIT(&sino->si_movs); - LIST_INSERT_HEAD(hd, sino, si_next); - - return (sino); -} - -/* - * Lookup a block number in the hash and allocate a suj_blk if it does - * not exist. - */ -static struct suj_blk * -blk_lookup(ufs2_daddr_t blk, int creat) -{ - struct suj_blk *sblk; - struct suj_cg *sc; - struct blkhd *hd; - - sc = cg_lookup(dtog(fs, blk)); - hd = &sc->sc_blkhash[SUJ_HASH(blk)]; - LIST_FOREACH(sblk, hd, sb_next) - if (sblk->sb_blk == blk) - return (sblk); - if (creat == 0) - return (NULL); - sblk = errmalloc(sizeof(*sblk)); - bzero(sblk, sizeof(*sblk)); - sblk->sb_blk = blk; - TAILQ_INIT(&sblk->sb_recs); - LIST_INSERT_HEAD(hd, sblk, sb_next); - - return (sblk); -} - -static uint8_t * -dblk_read(ufs2_daddr_t blk, int size) -{ - struct data_blk *dblk; - struct dblkhd *hd; - - hd = &dbhash[SUJ_HASH(blk)]; - LIST_FOREACH(dblk, hd, db_next) - if (dblk->db_blk == blk) - goto found; - /* - * The inode block wasn't located, allocate a new one. - */ - dblk = errmalloc(sizeof(*dblk)); - bzero(dblk, sizeof(*dblk)); - LIST_INSERT_HEAD(hd, dblk, db_next); - dblk->db_blk = blk; -found: - /* - * I doubt size mismatches can happen in practice but it is trivial - * to handle. - */ - if (size != dblk->db_size) { - if (dblk->db_buf) - free(dblk->db_buf); - dblk->db_buf = errmalloc(size); - dblk->db_size = size; - if (bread(disk, fsbtodb(fs, blk), dblk->db_buf, size) == -1) - err(1, "Failed to read data block %jd", blk); - } - return (dblk->db_buf); -} - -static union dinode * -ino_read(ino_t ino) -{ - struct ino_blk *iblk; - struct iblkhd *hd; - struct suj_cg *sc; - ufs2_daddr_t blk; - int off; - - blk = ino_to_fsba(fs, ino); - sc = cg_lookup(ino_to_cg(fs, ino)); - hd = &sc->sc_iblkhash[SUJ_HASH(blk)]; - LIST_FOREACH(iblk, hd, ib_next) - if (iblk->ib_blk == blk) - goto found; - /* - * The inode block wasn't located, allocate a new one. - */ - iblk = errmalloc(sizeof(*iblk)); - bzero(iblk, sizeof(*iblk)); - iblk->ib_buf = errmalloc(fs->fs_bsize); - iblk->ib_blk = blk; - LIST_INSERT_HEAD(hd, iblk, ib_next); - if (bread(disk, fsbtodb(fs, blk), iblk->ib_buf, fs->fs_bsize) == -1) - err(1, "Failed to read inode block %jd", blk); -found: - sc->sc_lastiblk = iblk; - off = ino_to_fsbo(fs, ino); - if (fs->fs_magic == FS_UFS1_MAGIC) - return (union dinode *)&((struct ufs1_dinode *)iblk->ib_buf)[off]; - else - return (union dinode *)&((struct ufs2_dinode *)iblk->ib_buf)[off]; -} - -static void -ino_dirty(ino_t ino) -{ - struct ino_blk *iblk; - struct iblkhd *hd; - struct suj_cg *sc; - ufs2_daddr_t blk; - - blk = ino_to_fsba(fs, ino); - sc = cg_lookup(ino_to_cg(fs, ino)); - iblk = sc->sc_lastiblk; - if (iblk && iblk->ib_blk == blk) { - iblk->ib_dirty = 1; - return; - } - hd = &sc->sc_iblkhash[SUJ_HASH(blk)]; - LIST_FOREACH(iblk, hd, ib_next) { - if (iblk->ib_blk == blk) { - iblk->ib_dirty = 1; - return; - } - } - ino_read(ino); - ino_dirty(ino); -} - -static void -iblk_write(struct ino_blk *iblk) -{ - - if (iblk->ib_dirty == 0) - return; - if (bwrite(disk, fsbtodb(fs, iblk->ib_blk), iblk->ib_buf, - fs->fs_bsize) == -1) - err(1, "Failed to write inode block %jd", iblk->ib_blk); -} - -/* - * Return 1 if the inode was free and 0 if it is allocated. - */ -static int -ino_isfree(ino_t ino) -{ - struct suj_cg *sc; - uint8_t *inosused; - struct cg *cgp; - int cg; - - cg = ino_to_cg(fs, ino); - ino = ino % fs->fs_ipg; - sc = cg_lookup(cg); - cgp = sc->sc_cgp; - inosused = cg_inosused(cgp); - return isclr(inosused, ino); -} - -static int -blk_overlaps(struct jblkrec *brec, ufs2_daddr_t start, int frags) -{ - ufs2_daddr_t bstart; - ufs2_daddr_t bend; - ufs2_daddr_t end; - - end = start + frags; - bstart = brec->jb_blkno + brec->jb_oldfrags; - bend = bstart + brec->jb_frags; - if (start < bend && end > bstart) - return (1); - return (0); -} - -static int -blk_equals(struct jblkrec *brec, ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t start, - int frags) -{ - - if (brec->jb_ino != ino || brec->jb_lbn != lbn) - return (0); - if (brec->jb_blkno + brec->jb_oldfrags != start) - return (0); - if (brec->jb_frags != frags) - return (0); - return (1); -} - -static void -blk_setmask(struct jblkrec *brec, int *mask) -{ - int i; - - for (i = brec->jb_oldfrags; i < brec->jb_oldfrags + brec->jb_frags; i++) - *mask |= 1 << i; -} - -/* - * Determine whether a given block has been reallocated to a new location. - * Returns a mask of overlapping bits if any frags have been reused or - * zero if the block has not been re-used and the contents can be trusted. - * - * This is used to ensure that an orphaned pointer due to truncate is safe - * to be freed. The mask value can be used to free partial blocks. - */ -static int -blk_isfree(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t lbn, int frags) -{ - struct suj_blk *sblk; - struct suj_rec *srec; - struct jblkrec *brec; - int mask; - int off; - - /* - * To be certain we're not freeing a reallocated block we lookup - * this block in the blk hash and see if there is an allocation - * journal record that overlaps with any fragments in the block - * we're concerned with. If any fragments have ben reallocated - * the block has already been freed and re-used for another purpose. - */ - mask = 0; - sblk = blk_lookup(blknum(fs, blk), 0); - if (sblk == NULL) - return (0); - off = blk - sblk->sb_blk; - TAILQ_FOREACH(srec, &sblk->sb_recs, sr_next) { - brec = (struct jblkrec *)srec->sr_rec; - /* - * If the block overlaps but does not match - * exactly it's a new allocation. If it matches - * exactly this record refers to the current - * location. - */ - if (blk_overlaps(brec, blk, frags) == 0) - continue; - if (blk_equals(brec, ino, lbn, blk, frags) == 1) - mask = 0; - else - blk_setmask(brec, &mask); - } - if (debug) - printf("blk_isfree: blk %jd sblk %jd off %d mask 0x%X\n", - blk, sblk->sb_blk, off, mask); - return (mask >> off); -} - -/* - * Determine whether it is safe to follow an indirect. It is not safe - * if any part of the indirect has been reallocated or the last journal - * entry was an allocation. Just allocated indirects may not have valid - * pointers yet and all of their children will have their own records. - * - * Returns 1 if it's safe to follow the indirect and 0 otherwise. - */ -static int -blk_isindir(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t lbn) -{ - struct suj_blk *sblk; - struct jblkrec *brec; - - sblk = blk_lookup(blk, 0); - if (sblk == NULL) - return (1); - if (TAILQ_EMPTY(&sblk->sb_recs)) - return (1); - brec = (struct jblkrec *)TAILQ_LAST(&sblk->sb_recs, srechd)->sr_rec; - if (blk_equals(brec, ino, lbn, blk, fs->fs_frag)) - if (brec->jb_op == JOP_FREEBLK) - return (1); - return (0); -} - -/* - * Clear an inode from the cg bitmap. If the inode was already clear return - * 0 so the caller knows it does not have to check the inode contents. - */ -static int -ino_free(ino_t ino, int mode) -{ - struct suj_cg *sc; - uint8_t *inosused; - struct cg *cgp; - int cg; - - cg = ino_to_cg(fs, ino); - ino = ino % fs->fs_ipg; - sc = cg_lookup(cg); - cgp = sc->sc_cgp; - inosused = cg_inosused(cgp); - /* - * The bitmap may never have made it to the disk so we have to - * conditionally clear. We can avoid writing the cg in this case. - */ - if (isclr(inosused, ino)) - return (0); - freeinos++; - clrbit(inosused, ino); - if (ino < cgp->cg_irotor) - cgp->cg_irotor = ino; - cgp->cg_cs.cs_nifree++; - if ((mode & IFMT) == IFDIR) { - freedir++; - cgp->cg_cs.cs_ndir--; - } - sc->sc_dirty = 1; - - return (1); -} - -/* - * Free 'frags' frags starting at filesystem block 'bno' skipping any frags - * set in the mask. - */ -static void -blk_free(ufs2_daddr_t bno, int mask, int frags) -{ - ufs1_daddr_t fragno, cgbno; - struct suj_cg *sc; - struct cg *cgp; - int i, cg; - uint8_t *blksfree; - - if (debug) - printf("Freeing %d frags at blk %jd\n", frags, bno); - cg = dtog(fs, bno); - sc = cg_lookup(cg); - cgp = sc->sc_cgp; - cgbno = dtogd(fs, bno); - blksfree = cg_blksfree(cgp); - - /* - * If it's not allocated we only wrote the journal entry - * and never the bitmaps. Here we unconditionally clear and - * resolve the cg summary later. - */ - if (frags == fs->fs_frag && mask == 0) { - fragno = fragstoblks(fs, cgbno); - ffs_setblock(fs, blksfree, fragno); - freeblocks++; - } else { - /* - * deallocate the fragment - */ - for (i = 0; i < frags; i++) - if ((mask & (1 << i)) == 0 && isclr(blksfree, cgbno +i)) { - freefrags++; - setbit(blksfree, cgbno + i); - } - } - sc->sc_dirty = 1; -} - -/* - * Fetch an indirect block to find the block at a given lbn. The lbn - * may be negative to fetch a specific indirect block pointer or positive - * to fetch a specific block. - */ -static ufs2_daddr_t -indir_blkatoff(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t cur, ufs_lbn_t lbn, int level) -{ - ufs2_daddr_t *bap2; - ufs2_daddr_t *bap1; - ufs_lbn_t lbnadd; - ufs_lbn_t base; - int i; - - if (blk == 0) - return (0); - if (cur == lbn) - return (blk); - if (level == 0 && lbn < 0) { - abort(); - errx(1, "Invalid lbn %jd", lbn); - } - bap2 = (void *)dblk_read(blk, fs->fs_bsize); - bap1 = (void *)bap2; - lbnadd = 1; - base = -(cur + level); - for (i = level; i > 0; i--) - lbnadd *= NINDIR(fs); - if (lbn > 0) - i = (lbn - base) / lbnadd; - else - i = (-lbn - base) / lbnadd; - if (i < 0 || i >= NINDIR(fs)) { - abort(); - errx(1, "Invalid indirect index %d produced by lbn %jd", - i, lbn); - } - if (level == 0) - cur = base + (i * lbnadd); - else - cur = -(base + (i * lbnadd)) - (level - 1); - if (fs->fs_magic == FS_UFS1_MAGIC) - blk = bap1[i]; - else - blk = bap2[i]; - if (cur == lbn) - return (blk); - if (level == 0) { - abort(); - errx(1, "Invalid lbn %jd at level 0", lbn); - } - return indir_blkatoff(blk, ino, cur, lbn, level - 1); -} - -/* - * Finds the disk block address at the specified lbn within the inode - * specified by ip. This follows the whole tree and honors di_size and - * di_extsize so it is a true test of reachability. The lbn may be - * negative if an extattr or indirect block is requested. - */ -static ufs2_daddr_t -ino_blkatoff(union dinode *ip, ino_t ino, ufs_lbn_t lbn, int *frags) -{ - ufs_lbn_t tmpval; - ufs_lbn_t cur; - ufs_lbn_t next; - int i; - - /* - * Handle extattr blocks first. - */ - if (lbn < 0 && lbn >= -NXADDR) { - lbn = -1 - lbn; - if (lbn > lblkno(fs, ip->dp2.di_extsize - 1)) - return (0); - *frags = numfrags(fs, sblksize(fs, ip->dp2.di_extsize, lbn)); - return (ip->dp2.di_extb[lbn]); - } - /* - * And now direct and indirect. Verify that the lbn does not - * exceed the size required to store the file by asking for - * the lbn of the last byte. These blocks should be 0 anyway - * so this simply saves the traversal. - */ - if (lbn > 0 && lbn > lblkno(fs, DIP(ip, di_size) - 1)) - return (0); - if (lbn < 0 && -lbn > lblkno(fs, DIP(ip, di_size) - 1)) - return (0); - if (lbn >= 0 && lbn < NDADDR) { - *frags = numfrags(fs, sblksize(fs, DIP(ip, di_size), lbn)); - return (DIP(ip, di_db[lbn])); - } - *frags = fs->fs_frag; - - for (i = 0, tmpval = NINDIR(fs), cur = NDADDR; i < NIADDR; i++, - tmpval *= NINDIR(fs), cur = next) { - next = cur + tmpval; - if (lbn == -cur) - return (DIP(ip, di_ib[i])); - /* - * Determine whether the lbn in question is within this tree. - */ - if (lbn < 0 && -lbn >= next) - continue; - if (lbn > 0 && lbn >= next) - continue; - - return indir_blkatoff(DIP(ip, di_ib[i]), ino, -cur - i, lbn, i); - } - errx(1, "lbn %jd not in ino", lbn); -} - -/* - * Determine whether a block exists at a particular lbn in an inode. - * Returns 1 if found, 0 if not. lbn may be negative for indirects - * or ext blocks. - */ -static int -blk_isat(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int *frags) -{ - union dinode *ip; - ufs2_daddr_t nblk; - - ip = ino_read(ino); - - if (DIP(ip, di_nlink) == 0 || DIP(ip, di_mode) == 0) - return (0); - nblk = ino_blkatoff(ip, ino, lbn, frags); - - return (nblk == blk); -} - -/* - * Determines whether a pointer to an inode exists within a directory - * at a specified offset. Returns the mode of the found entry. - */ -static int -ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot) -{ - union dinode *dip; - struct direct *dp; - ufs2_daddr_t blk; - uint8_t *block; - ufs_lbn_t lbn; - int blksize; - int frags; - int dpoff; - int doff; - - *isdot = 0; - dip = ino_read(parent); - *mode = DIP(dip, di_mode); - if ((*mode & IFMT) != IFDIR) { - if (debug) { - /* This can happen if the parent inode was reallocated. */ - if (*mode != 0) - printf("Directory %d has bad mode %o\n", - parent, *mode); - else - printf("Directory %d zero inode\n", parent); - } - return (0); - } - lbn = lblkno(fs, diroff); - doff = blkoff(fs, diroff); - blksize = sblksize(fs, DIP(dip, di_size), lbn); - if (diroff + DIRECTSIZ(1) > DIP(dip, di_size) || doff >= blksize) { - if (debug) - printf("ino %d absent from %d due to offset %jd" - " exceeding size %jd\n", - child, parent, diroff, DIP(dip, di_size)); - return (0); - } - blk = ino_blkatoff(dip, parent, lbn, &frags); - if (blk <= 0) { - if (debug) - printf("Sparse directory %d", parent); - return (0); - } - block = dblk_read(blk, blksize); - /* - * Walk through the records from the start of the block to be - * certain we hit a valid record and not some junk in the middle - * of a file name. Stop when we reach or pass the expected offset. - */ - dpoff = 0; - do { - dp = (struct direct *)&block[dpoff]; - if (dpoff == doff) - break; - if (dp->d_reclen == 0) - break; - dpoff += dp->d_reclen; - } while (dpoff <= doff); - if (dpoff > fs->fs_bsize) - errx(1, "Corrupt directory block in dir inode %d", parent); - /* Not found. */ - if (dpoff != doff) { - if (debug) - printf("ino %d not found in %d, lbn %jd, dpoff %d\n", - child, parent, lbn, dpoff); - return (0); - } - /* - * We found the item in question. Record the mode and whether it's - * a . or .. link for the caller. - */ - if (dp->d_ino == child) { - if (child == parent) - *isdot = 1; - else if (dp->d_namlen == 2 && - dp->d_name[0] == '.' && dp->d_name[1] == '.') - *isdot = 1; - *mode = DTTOIF(dp->d_type); - return (1); - } - if (debug) - printf("ino %d doesn't match dirent ino %d in parent %d\n", - child, dp->d_ino, parent); - return (0); -} - -#define VISIT_INDIR 0x0001 -#define VISIT_EXT 0x0002 - -/* - * Read an indirect level which may or may not be linked into an inode. - */ -static void -indir_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, uint64_t *frags, - ino_visitor visitor, int flags) -{ - ufs2_daddr_t *bap2; - ufs1_daddr_t *bap1; - ufs_lbn_t lbnadd; - ufs2_daddr_t nblk; - ufs_lbn_t nlbn; - int level; - int i; - - /* - * Don't visit indirect blocks with contents we can't trust. This - * should only happen when indir_visit() is called to complete a - * truncate that never finished and not when a pointer is found via - * an inode. - */ - if (blk == 0) - return; - if (blk_isindir(blk, ino, lbn) == 0) { - if (debug) - printf("blk %jd ino %d lbn %jd is not indir.\n", - blk, ino, lbn); - goto out; - } - level = lbn_level(lbn); - if (level == -1) { - abort(); - errx(1, "Invalid level for lbn %jd", lbn); - } - lbnadd = 1; - for (i = level; i > 0; i--) - lbnadd *= NINDIR(fs); - bap1 = (void *)dblk_read(blk, fs->fs_bsize); - bap2 = (void *)bap1; - for (i = 0; i < NINDIR(fs); i++) { - if (fs->fs_magic == FS_UFS1_MAGIC) - nblk = *bap1++; - else - nblk = *bap2++; - if (nblk == 0) - continue; - if (level == 0) { - nlbn = -lbn + i * lbnadd; - (*frags) += fs->fs_frag; - visitor(ino, nlbn, nblk, fs->fs_frag); - } else { - nlbn = (lbn + 1) - (i * lbnadd); - indir_visit(ino, nlbn, nblk, frags, visitor, flags); - } - } -out: - if (flags & VISIT_INDIR) { - (*frags) += fs->fs_frag; - visitor(ino, lbn, blk, fs->fs_frag); - } -} - -/* - * Visit each block in an inode as specified by 'flags' and call a - * callback function. The callback may inspect or free blocks. The - * count of frags found according to the size in the file is returned. - * This is not valid for sparse files but may be used to determine - * the correct di_blocks for a file. - */ -static uint64_t -ino_visit(union dinode *ip, ino_t ino, ino_visitor visitor, int flags) -{ - ufs_lbn_t tmpval; - ufs_lbn_t lbn; - uint64_t size; - uint64_t fragcnt; - int mode; - int frags; - int i; - - size = DIP(ip, di_size); - mode = DIP(ip, di_mode) & IFMT; - fragcnt = 0; - if ((flags & VISIT_EXT) && - fs->fs_magic == FS_UFS2_MAGIC && ip->dp2.di_extsize) { - for (i = 0; i < NXADDR; i++) { - if (ip->dp2.di_extb[i] == 0) - continue; - frags = sblksize(fs, ip->dp2.di_extsize, i); - frags = numfrags(fs, frags); - fragcnt += frags; - visitor(ino, -1 - i, ip->dp2.di_extb[i], frags); - } - } - /* Skip datablocks for short links and devices. */ - if (mode == IFBLK || mode == IFCHR || - (mode == IFLNK && size < fs->fs_maxsymlinklen)) - return (fragcnt); - for (i = 0; i < NDADDR; i++) { - if (DIP(ip, di_db[i]) == 0) - continue; - frags = sblksize(fs, size, i); - frags = numfrags(fs, frags); - fragcnt += frags; - visitor(ino, i, DIP(ip, di_db[i]), frags); - } - for (i = 0, tmpval = NINDIR(fs), lbn = NDADDR; i < NIADDR; i++, - tmpval *= NINDIR(fs), lbn += tmpval) { - if (DIP(ip, di_ib[i]) == 0) - continue; - indir_visit(ino, -lbn - i, DIP(ip, di_ib[i]), &fragcnt, visitor, - flags); - } - return (fragcnt); -} - -/* - * Null visitor function used when we just want to count blocks. - */ -static void -null_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags) -{ -} - -/* - * Recalculate di_blocks when we discover that a block allocation or - * free was not successfully completed. The kernel does not roll this back - * because it would be too expensive to compute which indirects were - * reachable at the time the inode was written. - */ -static void -ino_adjblks(ino_t ino) -{ - struct suj_ino *sino; - union dinode *ip; - uint64_t blocks; - uint64_t frags; - - sino = ino_lookup(ino, 1); - if (sino->si_blkadj) - return; - sino->si_blkadj = 1; - ip = ino_read(ino); - /* No need to adjust zero'd inodes. */ - if (DIP(ip, di_mode) == 0) - return; - frags = ino_visit(ip, ino, null_visit, VISIT_INDIR | VISIT_EXT); - blocks = fsbtodb(fs, frags); - if (blocks == DIP(ip, di_blocks)) - return; - if (debug) - printf("ino %d adjusting block count from %jd to %jd\n", - ino, DIP(ip, di_blocks), blocks); - DIP_SET(ip, di_blocks, blocks); - ino_dirty(ino); -} - -static void -blk_free_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags) -{ - int mask; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004240758.o3O7wxZA067332>