svn commit: r207144 - head/sbin/fsck_ffs

Jeff Roberson jroberson at jroberson.net
Sat Apr 24 09:02:52 UTC 2010


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 at 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 ***
>


More information about the svn-src-head mailing list