Date: Fri, 23 Apr 2010 22:40:45 -1000 (HST) From: Jeff Roberson <jroberson@jroberson.net> To: Pawel Jakub Dawidek <pjd@FreeBSD.org> Cc: svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org Subject: Re: svn commit: r207144 - head/sbin/fsck_ffs Message-ID: <alpine.BSF.2.00.1004232240080.1398@desktop> In-Reply-To: <201004240758.o3O7wxZA067332@svn.freebsd.org> References: <201004240758.o3O7wxZA067332@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, 24 Apr 2010, Pawel Jakub Dawidek wrote: > 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. Thanks pjd. I must've patched twice and not noticed. When I tried to just merge the changes from my projects branch it failed. Jeff > > 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?alpine.BSF.2.00.1004232240080.1398>