Ejemplo n.º 1
0
void
clearinode(ino_t inumber)
{
	struct ubuf *bp;
	IFILE *ifp;
	daddr_t daddr;

	/* Send cleared inode to the free list */

	LFS_IENTRY(ifp, fs, inumber, bp);
	daddr = ifp->if_daddr;
	if (daddr == LFS_UNUSED_DADDR) {
		brelse(bp, 0);
		return;
	}
	ifp->if_daddr = LFS_UNUSED_DADDR;
	ifp->if_nextfree = fs->lfs_freehd;
	fs->lfs_freehd = inumber;
	sbdirty();
	VOP_BWRITE(bp);

	/*
	 * update segment usage.
	 */
	if (daddr != LFS_UNUSED_DADDR) {
		SEGUSE *sup;
		u_int32_t oldsn = dtosn(fs, daddr);

		seg_table[oldsn].su_nbytes -= DINODE1_SIZE;
		LFS_SEGENTRY(sup, fs, oldsn, bp);
		sup->su_nbytes -= DINODE1_SIZE;
		LFS_WRITESEGENTRY(sup, fs, oldsn, bp);	/* Ifile */
	}
}
Ejemplo n.º 2
0
static void
lfs_finalize_seguse(struct lfs *fs, void *v)
{
	SEGUSE *sup;
	struct buf *bp;
	struct segdelta *sd;
	LIST_HEAD(, segdelta) *hd = v;

	ASSERT_SEGLOCK(fs);
	while((sd = LIST_FIRST(hd)) != NULL) {
		LIST_REMOVE(sd, list);
		LFS_SEGENTRY(sup, fs, sd->segnum, bp);
		if (sd->num > sup->su_nbytes) {
			printf("lfs_finalize_seguse: segment %ld short by %ld\n",
				sd->segnum, (long)(sd->num - sup->su_nbytes));
			panic("lfs_finalize_seguse: negative bytes");
			sup->su_nbytes = sd->num;
		}
		sup->su_nbytes -= sd->num;
		LFS_WRITESEGENTRY(sup, fs, sd->segnum, bp);
		free(sd, M_SEGMENT);
	}
}
Ejemplo n.º 3
0
static int
update_inoblk(struct lfs *fs, daddr_t offset, kauth_cred_t cred,
	      struct lwp *l)
{
	struct vnode *devvp, *vp;
	struct inode *ip;
	struct ufs1_dinode *dip;
	struct buf *dbp, *ibp;
	int error;
	daddr_t daddr;
	IFILE *ifp;
	SEGUSE *sup;

	devvp = VTOI(fs->lfs_ivnode)->i_devvp;

	/*
	 * Get the inode, update times and perms.
	 * DO NOT update disk blocks, we do that separately.
	 */
	error = bread(devvp, fsbtodb(fs, offset), fs->lfs_ibsize,
	    cred, 0, &dbp);
	if (error) {
		DLOG((DLOG_RF, "update_inoblk: bread returned %d\n", error));
		return error;
	}
	dip = ((struct ufs1_dinode *)(dbp->b_data)) + INOPB(fs);
	while (--dip >= (struct ufs1_dinode *)dbp->b_data) {
		if (dip->di_inumber > LFS_IFILE_INUM) {
			error = lfs_rf_valloc(fs, dip->di_inumber, dip->di_gen,
					      l, &vp);
			if (error) {
				DLOG((DLOG_RF, "update_inoblk: lfs_rf_valloc"
				      " returned %d\n", error));
				continue;
			}
			ip = VTOI(vp);
			if (dip->di_size != ip->i_size)
				lfs_truncate(vp, dip->di_size, 0, NOCRED);
			/* Get mode, link count, size, and times */
			memcpy(ip->i_din.ffs1_din, dip,
			       offsetof(struct ufs1_dinode, di_db[0]));

			/* Then the rest, except di_blocks */
			ip->i_flags = ip->i_ffs1_flags = dip->di_flags;
			ip->i_gen = ip->i_ffs1_gen = dip->di_gen;
			ip->i_uid = ip->i_ffs1_uid = dip->di_uid;
			ip->i_gid = ip->i_ffs1_gid = dip->di_gid;

			ip->i_mode = ip->i_ffs1_mode;
			ip->i_nlink = ip->i_ffs1_nlink;
			ip->i_size = ip->i_ffs1_size;

			LFS_SET_UINO(ip, IN_CHANGE | IN_UPDATE);

			/* Re-initialize to get type right */
			ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p,
				  &vp);
			vput(vp);

			/* Record change in location */
			LFS_IENTRY(ifp, fs, dip->di_inumber, ibp);
			daddr = ifp->if_daddr;
			ifp->if_daddr = dbtofsb(fs, dbp->b_blkno);
			error = LFS_BWRITE_LOG(ibp); /* Ifile */
			/* And do segment accounting */
			if (dtosn(fs, daddr) != dtosn(fs, dbtofsb(fs, dbp->b_blkno))) {
				if (daddr > 0) {
					LFS_SEGENTRY(sup, fs, dtosn(fs, daddr),
						     ibp);
					sup->su_nbytes -= sizeof (struct ufs1_dinode);
					LFS_WRITESEGENTRY(sup, fs,
							  dtosn(fs, daddr),
							  ibp);
				}
				LFS_SEGENTRY(sup, fs, dtosn(fs, dbtofsb(fs, dbp->b_blkno)),
					     ibp);
				sup->su_nbytes += sizeof (struct ufs1_dinode);
				LFS_WRITESEGENTRY(sup, fs,
						  dtosn(fs, dbtofsb(fs, dbp->b_blkno)),
						  ibp);
			}
		}
	}
Ejemplo n.º 4
0
/*
 * Load the appropriate indirect block, and change the appropriate pointer.
 * Mark the block dirty.  Do segment and avail accounting.
 */
static int
update_meta(struct lfs *fs, ino_t ino, int vers, daddr_t lbn,
	    daddr_t ndaddr, size_t size, struct lwp *l)
{
	int error;
	struct vnode *vp;
	struct inode *ip;
#ifdef DEBUG
	daddr_t odaddr;
	struct indir a[NIADDR];
	int num;
	int i;
#endif /* DEBUG */
	struct buf *bp;
	SEGUSE *sup;

	KASSERT(lbn >= 0);	/* no indirect blocks */

	if ((error = lfs_rf_valloc(fs, ino, vers, l, &vp)) != 0) {
		DLOG((DLOG_RF, "update_meta: ino %d: lfs_rf_valloc"
		      " returned %d\n", ino, error));
		return error;
	}

	if ((error = lfs_balloc(vp, (lbn << fs->lfs_bshift), size,
				NOCRED, 0, &bp)) != 0) {
		vput(vp);
		return (error);
	}
	/* No need to write, the block is already on disk */
	if (bp->b_oflags & BO_DELWRI) {
		LFS_UNLOCK_BUF(bp);
		fs->lfs_avail += btofsb(fs, bp->b_bcount);
	}
	brelse(bp, BC_INVAL);

	/*
	 * Extend the file, if it is not large enough already.
	 * XXX this is not exactly right, we don't know how much of the
	 * XXX last block is actually used.  We hope that an inode will
	 * XXX appear later to give the correct size.
	 */
	ip = VTOI(vp);
	if (ip->i_size <= (lbn << fs->lfs_bshift)) {
		u_int64_t newsize;

		if (lbn < NDADDR)
			newsize = ip->i_ffs1_size = (lbn << fs->lfs_bshift) +
				(size - fs->lfs_fsize) + 1;
		else
			newsize = ip->i_ffs1_size = (lbn << fs->lfs_bshift) + 1;

		if (ip->i_size < newsize) {
			ip->i_size = newsize;
			/*
			 * tell vm our new size for the case the inode won't
			 * appear later.
			 */
			uvm_vnp_setsize(vp, newsize);
		}
	}

	lfs_update_single(fs, NULL, vp, lbn, ndaddr, size);

	LFS_SEGENTRY(sup, fs, dtosn(fs, ndaddr), bp);
	sup->su_nbytes += size;
	LFS_WRITESEGENTRY(sup, fs, dtosn(fs, ndaddr), bp);

	/* differences here should be due to UNWRITTEN indirect blocks. */
	KASSERT((lblkno(fs, ip->i_size) > NDADDR &&
	    ip->i_lfs_effnblks == ip->i_ffs1_blocks) ||
	    ip->i_lfs_effnblks >= ip->i_ffs1_blocks);

#ifdef DEBUG
	/* Now look again to make sure it worked */
	ufs_bmaparray(vp, lbn, &odaddr, &a[0], &num, NULL, NULL);
	for (i = num; i > 0; i--) {
		if (!a[i].in_exists)
			panic("update_meta: absent %d lv indirect block", i);
	}
	if (dbtofsb(fs, odaddr) != ndaddr)
		DLOG((DLOG_RF, "update_meta: failed setting ino %d lbn %"
		      PRId64 " to %" PRId64 "\n", ino, lbn, ndaddr));
#endif /* DEBUG */
	vput(vp);
	return 0;
}
Ejemplo n.º 5
0
/*
 * Actually mark the segment clean.
 * Must be called with the segment lock held.
 */
int
lfs_do_segclean(struct lfs *fs, unsigned long segnum)
{
	extern int lfs_dostats;
	struct buf *bp;
	CLEANERINFO *cip;
	SEGUSE *sup;

	if (lfs_dtosn(fs, fs->lfs_curseg) == segnum) {
		return (EBUSY);
	}

	LFS_SEGENTRY(sup, fs, segnum, bp);
	if (sup->su_nbytes) {
		DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:"
		      " %d live bytes\n", segnum, sup->su_nbytes));
		brelse(bp, 0);
		return (EBUSY);
	}
	if (sup->su_flags & SEGUSE_ACTIVE) {
		DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:"
		      " segment is active\n", segnum));
		brelse(bp, 0);
		return (EBUSY);
	}
	if (!(sup->su_flags & SEGUSE_DIRTY)) {
		DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:"
		      " segment is already clean\n", segnum));
		brelse(bp, 0);
		return (EALREADY);
	}

	fs->lfs_avail += lfs_segtod(fs, 1);
	if (sup->su_flags & SEGUSE_SUPERBLOCK)
		fs->lfs_avail -= lfs_btofsb(fs, LFS_SBPAD);
	if (fs->lfs_version > 1 && segnum == 0 &&
	    fs->lfs_start < lfs_btofsb(fs, LFS_LABELPAD))
		fs->lfs_avail -= lfs_btofsb(fs, LFS_LABELPAD) - fs->lfs_start;
	mutex_enter(&lfs_lock);
	fs->lfs_bfree += sup->su_nsums * lfs_btofsb(fs, fs->lfs_sumsize) +
		lfs_btofsb(fs, sup->su_ninos * fs->lfs_ibsize);
	fs->lfs_dmeta -= sup->su_nsums * lfs_btofsb(fs, fs->lfs_sumsize) +
		lfs_btofsb(fs, sup->su_ninos * fs->lfs_ibsize);
	if (fs->lfs_dmeta < 0)
		fs->lfs_dmeta = 0;
	mutex_exit(&lfs_lock);
	sup->su_flags &= ~SEGUSE_DIRTY;
	LFS_WRITESEGENTRY(sup, fs, segnum, bp);

	LFS_CLEANERINFO(cip, fs, bp);
	++cip->clean;
	--cip->dirty;
	fs->lfs_nclean = cip->clean;
	cip->bfree = fs->lfs_bfree;
	mutex_enter(&lfs_lock);
	cip->avail = fs->lfs_avail - fs->lfs_ravail - fs->lfs_favail;
	wakeup(&fs->lfs_avail);
	mutex_exit(&lfs_lock);
	(void) LFS_BWRITE_LOG(bp);

	if (lfs_dostats)
		++lfs_stats.segs_reclaimed;

	return (0);
}
Ejemplo n.º 6
0
int
setup(const char *dev)
{
	long bmapsize;
	struct stat statb;
	int doskipclean;
	u_int64_t maxfilesize;
	int open_flags;
	struct uvnode *ivp;
	struct ubuf *bp;
	int i, isdirty;
	long sn, curseg;
	SEGUSE *sup;

	havesb = 0;
	doskipclean = skipclean;
	if (stat(dev, &statb) < 0) {
		pfatal("Can't stat %s: %s\n", dev, strerror(errno));
		return (0);
	}
	if (!S_ISCHR(statb.st_mode) && skipclean) {
		pfatal("%s is not a character device", dev);
		if (reply("CONTINUE") == 0)
			return (0);
	}
	if (nflag)
		open_flags = O_RDONLY;
	else
		open_flags = O_RDWR;

	if ((fsreadfd = open(dev, open_flags)) < 0) {
		pfatal("Can't open %s: %s\n", dev, strerror(errno));
		return (0);
	}
	if (nflag) {
		if (preen)
			pfatal("NO WRITE ACCESS");
		printf("** %s (NO WRITE)\n", dev);
		quiet = 0;
	} else if (!preen && !quiet)
		printf("** %s\n", dev);

	fsmodified = 0;
	lfdir = 0;

	/* Initialize time in case we have to write */
	time(&write_time);

	bufinit(0); /* XXX we could make a better guess */
	fs = lfs_init(fsreadfd, bflag, idaddr, 0, debug);
	if (fs == NULL) {
		if (preen)
			printf("%s: ", cdevname());
		errexit("BAD SUPER BLOCK OR IFILE INODE NOT FOUND");
	}

        /* Resize buffer cache now that we have a superblock to guess from. */ 
        bufrehash((fs->lfs_segtabsz + maxino / fs->lfs_ifpb) << 4);

	if (fs->lfs_pflags & LFS_PF_CLEAN) {
		if (doskipclean) {
			if (!quiet)
				pwarn("%sile system is clean; not checking\n",
				      preen ? "f" : "** F");
			return (-1);
		}
		if (!preen)
			pwarn("** File system is already clean\n");
	}

	if (idaddr) {
		daddr_t tdaddr;
		SEGSUM *sp;
		FINFO *fp;
		int bc;

		if (debug)
			pwarn("adjusting offset, serial for -i 0x%lx\n",
				(unsigned long)idaddr);
		tdaddr = lfs_sntod(fs, lfs_dtosn(fs, idaddr));
		if (lfs_sntod(fs, lfs_dtosn(fs, tdaddr)) == tdaddr) {
			if (tdaddr == fs->lfs_start)
				tdaddr += lfs_btofsb(fs, LFS_LABELPAD);
			for (i = 0; i < LFS_MAXNUMSB; i++) {
				if (fs->lfs_sboffs[i] == tdaddr)
					tdaddr += lfs_btofsb(fs, LFS_SBPAD);
				if (fs->lfs_sboffs[i] > tdaddr)
					break;
			}
		}
		fs->lfs_offset = tdaddr;
		if (debug)
			pwarn("begin with offset/serial 0x%x/%d\n",
				(int)fs->lfs_offset, (int)fs->lfs_serial);
		while (tdaddr < idaddr) {
			bread(fs->lfs_devvp, LFS_FSBTODB(fs, tdaddr),
			      fs->lfs_sumsize,
			      NULL, 0, &bp);
			sp = (SEGSUM *)bp->b_data;
			if (sp->ss_sumsum != cksum(&sp->ss_datasum,
						   fs->lfs_sumsize -
						   sizeof(sp->ss_sumsum))) {
				brelse(bp, 0);
				if (debug)
					printf("bad cksum at %x\n",
					       (unsigned)tdaddr);
				break;
			}
			fp = (FINFO *)(sp + 1);
			bc = howmany(sp->ss_ninos, LFS_INOPB(fs)) <<
				(fs->lfs_version > 1 ? fs->lfs_ffshift :
						       fs->lfs_bshift);
			for (i = 0; i < sp->ss_nfinfo; i++) {
				bc += fp->fi_lastlength + ((fp->fi_nblocks - 1)
					<< fs->lfs_bshift);
				fp = (FINFO *)(fp->fi_blocks + fp->fi_nblocks);
			}

			tdaddr += lfs_btofsb(fs, bc) + 1;
			fs->lfs_offset = tdaddr;
			fs->lfs_serial = sp->ss_serial + 1;
			brelse(bp, 0);
		}

		/*
		 * Set curseg, nextseg appropriately -- inlined from
		 * lfs_newseg()
		 */
		curseg = lfs_dtosn(fs, fs->lfs_offset);
		fs->lfs_curseg = lfs_sntod(fs, curseg);
		for (sn = curseg + fs->lfs_interleave;;) {  
			sn = (sn + 1) % fs->lfs_nseg;
			if (sn == curseg)
				errx(1, "init: no clean segments");
			LFS_SEGENTRY(sup, fs, sn, bp);
			isdirty = sup->su_flags & SEGUSE_DIRTY;
			brelse(bp, 0);

			if (!isdirty)
				break;
		}

		/* Skip superblock if necessary */
		for (i = 0; i < LFS_MAXNUMSB; i++)
			if (fs->lfs_offset == fs->lfs_sboffs[i])
				fs->lfs_offset += lfs_btofsb(fs, LFS_SBPAD);

		++fs->lfs_nactive;
		fs->lfs_nextseg = lfs_sntod(fs, sn);
		if (debug) {
			pwarn("offset = 0x%" PRIx32 ", serial = %" PRId64 "\n",
				fs->lfs_offset, fs->lfs_serial);
			pwarn("curseg = %" PRIx32 ", nextseg = %" PRIx32 "\n",
				fs->lfs_curseg, fs->lfs_nextseg);
		}

		if (!nflag && !skipclean) {
			fs->lfs_idaddr = idaddr;
			fsmodified = 1;
			sbdirty();
		}
	}

	if (debug) {
		pwarn("idaddr    = 0x%lx\n", idaddr ? (unsigned long)idaddr :
			(unsigned long)fs->lfs_idaddr);
		pwarn("dev_bsize = %lu\n", dev_bsize);
		pwarn("lfs_bsize = %lu\n", (unsigned long) fs->lfs_bsize);
		pwarn("lfs_fsize = %lu\n", (unsigned long) fs->lfs_fsize);
		pwarn("lfs_frag  = %lu\n", (unsigned long) fs->lfs_frag);
		pwarn("lfs_inopb = %lu\n", (unsigned long) fs->lfs_inopb);
	}
	if (fs->lfs_version == 1)
		maxfsblock = fs->lfs_size * (fs->lfs_bsize / dev_bsize);
	else
		maxfsblock = fs->lfs_size;
	maxfilesize = calcmaxfilesize(fs->lfs_bshift);
	if (/* fs->lfs_minfree < 0 || */ fs->lfs_minfree > 99) {
		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
		    fs->lfs_minfree);
		if (reply("SET TO DEFAULT") == 1) {
			fs->lfs_minfree = 10;
			sbdirty();
		}
	}
	if (fs->lfs_bmask != fs->lfs_bsize - 1) {
		pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK (SHOULD BE 0x%x)",
		    (unsigned int) fs->lfs_bmask,
		    (unsigned int) fs->lfs_bsize - 1);
		fs->lfs_bmask = fs->lfs_bsize - 1;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
		}
	}
	if (fs->lfs_ffmask != fs->lfs_fsize - 1) {
		pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK",
		    fs->lfs_ffmask);
		fs->lfs_ffmask = fs->lfs_fsize - 1;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
		}
	}
	if (fs->lfs_fbmask != (1 << fs->lfs_fbshift) - 1) {
		pwarn("INCORRECT FBMASK=%" PRId64 " IN SUPERBLOCK",
		    fs->lfs_fbmask);
		fs->lfs_fbmask = (1 << fs->lfs_fbshift) - 1;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
		}
	}
	if (fs->lfs_maxfilesize != maxfilesize) {
		pwarn(
		    "INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK (SHOULD BE %llu WITH BSHIFT %d)",
		    (unsigned long long) fs->lfs_maxfilesize,
		    (unsigned long long) maxfilesize, (int)fs->lfs_bshift);
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			fs->lfs_maxfilesize = maxfilesize;
			sbdirty();
		}
	}
	if (fs->lfs_maxsymlinklen != ULFS1_MAXSYMLINKLEN) {
		pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
		    fs->lfs_maxsymlinklen);
		fs->lfs_maxsymlinklen = ULFS1_MAXSYMLINKLEN;
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
		}
	}

	/*
	 * Read in the Ifile; we'll be using it a lot.
	 * XXX If the Ifile is corrupted we are in bad shape.  We need to
	 * XXX run through the segment headers of the entire disk to
	 * XXX reconstruct the inode table, then pretend all segments are
	 * XXX dirty while we do the rest.
	 */
	ivp = fs->lfs_ivnode;
	maxino = ((VTOI(ivp)->i_ffs1_size - (fs->lfs_cleansz + fs->lfs_segtabsz)
		* fs->lfs_bsize) / fs->lfs_bsize) * fs->lfs_ifpb;
	if (debug)
		pwarn("maxino    = %llu\n", (unsigned long long)maxino);
	for (i = 0; i < VTOI(ivp)->i_ffs1_size; i += fs->lfs_bsize) {
		bread(ivp, i >> fs->lfs_bshift, fs->lfs_bsize, NOCRED, 0, &bp);
		/* XXX check B_ERROR */
		brelse(bp, 0);
	}

	/*
	 * allocate and initialize the necessary maps
	 */
	din_table = ecalloc(maxino, sizeof(*din_table));
	seg_table = ecalloc(fs->lfs_nseg, sizeof(SEGUSE));
	/* Get segment flags */
	for (i = 0; i < fs->lfs_nseg; i++) {
		LFS_SEGENTRY(sup, fs, i, bp);
		seg_table[i].su_flags = sup->su_flags & ~SEGUSE_ACTIVE;
		if (preen)
			seg_table[i].su_nbytes = sup->su_nbytes;
		brelse(bp, 0);
	}

	/* Initialize Ifile entry */
	din_table[fs->lfs_ifile] = fs->lfs_idaddr;
	seg_table[lfs_dtosn(fs, fs->lfs_idaddr)].su_nbytes += LFS_DINODE1_SIZE;

#ifndef VERBOSE_BLOCKMAP
	bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
	blockmap = ecalloc(bmapsize, sizeof(char));
#else
	bmapsize = maxfsblock * sizeof(ino_t);
	blockmap = ecalloc(maxfsblock, sizeof(ino_t));
#endif
	statemap = ecalloc(maxino, sizeof(char));
	typemap = ecalloc(maxino, sizeof(char));
	lncntp = ecalloc(maxino, sizeof(int16_t));

	if (preen) {
		n_files = fs->lfs_nfiles;
		n_blks  = fs->lfs_dsize - fs->lfs_bfree;
		numdirs = maxino;
		inplast = 0; 
		listmax = numdirs + 10;
		inpsort = ecalloc(listmax, sizeof(struct inoinfo *));
		inphead = ecalloc(numdirs, sizeof(struct inoinfo *));
	}

	return (1);

	ckfini(0);
	return (0);
}
Ejemplo n.º 7
0
int
setup(const char *dev)
{
#ifndef VERBOSE_BLOCKMAP
	long bmapsize;
#endif
	struct stat statb;
	int doskipclean;
	u_int64_t maxfilesize;
	int open_flags;
	struct uvnode *ivp;
	struct ubuf *bp;
	int i, isdirty;
	long sn, curseg;
	SEGUSE *sup;
	size_t sumstart;

	havesb = 0;
	doskipclean = skipclean;
	if (stat(dev, &statb) < 0) {
		pfatal("Can't stat %s: %s\n", dev, strerror(errno));
		return (0);
	}
	if (!S_ISCHR(statb.st_mode) && skipclean) {
		pfatal("%s is not a character device", dev);
		if (reply("CONTINUE") == 0)
			return (0);
	}
	if (nflag)
		open_flags = O_RDONLY;
	else
		open_flags = O_RDWR;

	if ((fsreadfd = open(dev, open_flags)) < 0) {
		pfatal("Can't open %s: %s\n", dev, strerror(errno));
		return (0);
	}
	if (nflag) {
		if (preen)
			pfatal("NO WRITE ACCESS");
		printf("** %s (NO WRITE)\n", dev);
		quiet = 0;
	} else if (!preen && !quiet)
		printf("** %s\n", dev);

	fsmodified = 0;
	lfdir = 0;

	/* Initialize time in case we have to write */
	time(&write_time);

	bufinit(0); /* XXX we could make a better guess */
	fs = lfs_init(fsreadfd, bflag, idaddr, 0, debug);
	if (fs == NULL) {
		if (preen)
			printf("%s: ", cdevname());
		errexit("BAD SUPER BLOCK OR IFILE INODE NOT FOUND");
	}

        /* Resize buffer cache now that we have a superblock to guess from. */ 
        bufrehash((lfs_sb_getsegtabsz(fs) + maxino / lfs_sb_getifpb(fs)) << 4);

	if (lfs_sb_getpflags(fs) & LFS_PF_CLEAN) {
		if (doskipclean) {
			if (!quiet)
				pwarn("%sile system is clean; not checking\n",
				      preen ? "f" : "** F");
			return (-1);
		}
		if (!preen)
			pwarn("** File system is already clean\n");
	}

	if (idaddr) {
		daddr_t tdaddr;
		SEGSUM *sp;
		FINFO *fp;
		int bc;

		if (debug)
			pwarn("adjusting offset, serial for -i 0x%jx\n",
				(uintmax_t)idaddr);
		tdaddr = lfs_sntod(fs, lfs_dtosn(fs, idaddr));
		if (lfs_sntod(fs, lfs_dtosn(fs, tdaddr)) == tdaddr) {
			if (tdaddr == lfs_sb_gets0addr(fs))
				tdaddr += lfs_btofsb(fs, LFS_LABELPAD);
			for (i = 0; i < LFS_MAXNUMSB; i++) {
				if (lfs_sb_getsboff(fs, i) == tdaddr)
					tdaddr += lfs_btofsb(fs, LFS_SBPAD);
				if (lfs_sb_getsboff(fs, i) > tdaddr)
					break;
			}
		}
		lfs_sb_setoffset(fs, tdaddr);
		if (debug)
			pwarn("begin with offset/serial 0x%jx/%jd\n",
				(uintmax_t)lfs_sb_getoffset(fs),
				(intmax_t)lfs_sb_getserial(fs));
		while (tdaddr < idaddr) {
			bread(fs->lfs_devvp, LFS_FSBTODB(fs, tdaddr),
			      lfs_sb_getsumsize(fs),
			      0, &bp);
			sp = (SEGSUM *)bp->b_data;
			sumstart = lfs_ss_getsumstart(fs);
			if (lfs_ss_getsumsum(fs, sp) !=
			    cksum((char *)sp + sumstart,
				  lfs_sb_getsumsize(fs) - sumstart)) {
				brelse(bp, 0);
				if (debug)
					printf("bad cksum at %jx\n",
					       (uintmax_t)tdaddr);
				break;
			}
			fp = SEGSUM_FINFOBASE(fs, sp);
			bc = howmany(lfs_ss_getninos(fs, sp), LFS_INOPB(fs)) <<
				(lfs_sb_getversion(fs) > 1 ? lfs_sb_getffshift(fs) :
						       lfs_sb_getbshift(fs));
			for (i = 0; i < lfs_ss_getnfinfo(fs, sp); i++) {
				bc += lfs_fi_getlastlength(fs, fp) + ((lfs_fi_getnblocks(fs, fp) - 1)
					<< lfs_sb_getbshift(fs));
				fp = NEXT_FINFO(fs, fp);
			}

			tdaddr += lfs_btofsb(fs, bc) + 1;
			lfs_sb_setoffset(fs, tdaddr);
			lfs_sb_setserial(fs, lfs_ss_getserial(fs, sp) + 1);
			brelse(bp, 0);
		}

		/*
		 * Set curseg, nextseg appropriately -- inlined from
		 * lfs_newseg()
		 */
		curseg = lfs_dtosn(fs, lfs_sb_getoffset(fs));
		lfs_sb_setcurseg(fs, lfs_sntod(fs, curseg));
		for (sn = curseg + lfs_sb_getinterleave(fs);;) {  
			sn = (sn + 1) % lfs_sb_getnseg(fs);
			if (sn == curseg)
				errx(1, "init: no clean segments");
			LFS_SEGENTRY(sup, fs, sn, bp);
			isdirty = sup->su_flags & SEGUSE_DIRTY;
			brelse(bp, 0);

			if (!isdirty)
				break;
		}

		/* Skip superblock if necessary */
		for (i = 0; i < LFS_MAXNUMSB; i++)
			if (lfs_sb_getoffset(fs) == lfs_sb_getsboff(fs, i))
				lfs_sb_addoffset(fs, lfs_btofsb(fs, LFS_SBPAD));

		++fs->lfs_nactive;
		lfs_sb_setnextseg(fs, lfs_sntod(fs, sn));
		if (debug) {
			pwarn("offset = 0x%" PRIx64 ", serial = %" PRIu64 "\n",
				lfs_sb_getoffset(fs), lfs_sb_getserial(fs));
			pwarn("curseg = %" PRIx64 ", nextseg = %" PRIx64 "\n",
				lfs_sb_getcurseg(fs), lfs_sb_getnextseg(fs));
		}

		if (!nflag && !skipclean) {
			lfs_sb_setidaddr(fs, idaddr);
			fsmodified = 1;
			sbdirty();
		}
	}

	if (debug) {
		pwarn("idaddr    = 0x%jx\n", idaddr ? (uintmax_t)idaddr :
			(uintmax_t)lfs_sb_getidaddr(fs));
		pwarn("dev_bsize = %lu\n", dev_bsize);
		pwarn("lfs_bsize = %lu\n", (unsigned long) lfs_sb_getbsize(fs));
		pwarn("lfs_fsize = %lu\n", (unsigned long) lfs_sb_getfsize(fs));
		pwarn("lfs_frag  = %lu\n", (unsigned long) lfs_sb_getfrag(fs));
		pwarn("lfs_inopb = %lu\n", (unsigned long) lfs_sb_getinopb(fs));
	}
	if (lfs_sb_getversion(fs) == 1)
		maxfsblock = lfs_blkstofrags(fs, lfs_sb_getsize(fs));
	else
		maxfsblock = lfs_sb_getsize(fs);
	maxfilesize = calcmaxfilesize(lfs_sb_getbshift(fs));
	if (/* lfs_sb_getminfree(fs) < 0 || */ lfs_sb_getminfree(fs) > 99) {
		pfatal("IMPOSSIBLE MINFREE=%u IN SUPERBLOCK",
		    lfs_sb_getminfree(fs));
		if (reply("SET TO DEFAULT") == 1) {
			lfs_sb_setminfree(fs, 10);
			sbdirty();
		}
	}
	if (lfs_sb_getbmask(fs) != lfs_sb_getbsize(fs) - 1) {
		pwarn("INCORRECT BMASK=0x%jx IN SUPERBLOCK (SHOULD BE 0x%x)",
		    (uintmax_t)lfs_sb_getbmask(fs),
		    lfs_sb_getbsize(fs) - 1);
		lfs_sb_setbmask(fs, lfs_sb_getbsize(fs) - 1);
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
		}
	}
	if (lfs_sb_getffmask(fs) != lfs_sb_getfsize(fs) - 1) {
		pwarn("INCORRECT FFMASK=0x%jx IN SUPERBLOCK (SHOULD BE 0x%x)",
		    (uintmax_t)lfs_sb_getffmask(fs),
		    lfs_sb_getfsize(fs) - 1);
		lfs_sb_setffmask(fs, lfs_sb_getfsize(fs) - 1);
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
		}
	}
	if (lfs_sb_getfbmask(fs) != (1U << lfs_sb_getfbshift(fs)) - 1) {
		pwarn("INCORRECT FBMASK=0x%jx IN SUPERBLOCK (SHOULD BE 0x%x)",
		    (uintmax_t)lfs_sb_getfbmask(fs),
		      (1U << lfs_sb_getfbshift(fs)) - 1);
		lfs_sb_setfbmask(fs, (1U << lfs_sb_getfbshift(fs)) - 1);
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
		}
	}
	if (lfs_sb_getmaxfilesize(fs) != maxfilesize) {
		pwarn(
		    "INCORRECT MAXFILESIZE=%ju IN SUPERBLOCK (SHOULD BE %ju WITH BSHIFT %u)",
		    (uintmax_t) lfs_sb_getmaxfilesize(fs),
		    (uintmax_t) maxfilesize, lfs_sb_getbshift(fs));
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			lfs_sb_setmaxfilesize(fs, maxfilesize);
			sbdirty();
		}
	}
	if (lfs_sb_getmaxsymlinklen(fs) != LFS_MAXSYMLINKLEN(fs)) {
		pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK (SHOULD BE %zu)",
		    lfs_sb_getmaxsymlinklen(fs), LFS_MAXSYMLINKLEN(fs));
		lfs_sb_setmaxsymlinklen(fs, LFS_MAXSYMLINKLEN(fs));
		if (preen)
			printf(" (FIXED)\n");
		if (preen || reply("FIX") == 1) {
			sbdirty();
		}
	}

	/*
	 * Read in the Ifile; we'll be using it a lot.
	 * XXX If the Ifile is corrupted we are in bad shape.  We need to
	 * XXX run through the segment headers of the entire disk to
	 * XXX reconstruct the inode table, then pretend all segments are
	 * XXX dirty while we do the rest.
	 */
	ivp = fs->lfs_ivnode;
	maxino = ((lfs_dino_getsize(fs, VTOI(ivp)->i_din) - (lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs))
		* lfs_sb_getbsize(fs)) / lfs_sb_getbsize(fs)) * lfs_sb_getifpb(fs);
	if (debug)
		pwarn("maxino    = %llu\n", (unsigned long long)maxino);
	for (i = 0; i < lfs_dino_getsize(fs, VTOI(ivp)->i_din); i += lfs_sb_getbsize(fs)) {
		bread(ivp, i >> lfs_sb_getbshift(fs), lfs_sb_getbsize(fs), 0, &bp);
		/* XXX check B_ERROR */
		brelse(bp, 0);
	}

	/*
	 * allocate and initialize the necessary maps
	 */
	din_table = ecalloc(maxino, sizeof(*din_table));
	seg_table = ecalloc(lfs_sb_getnseg(fs), sizeof(SEGUSE));
	/* Get segment flags */
	for (i = 0; i < lfs_sb_getnseg(fs); i++) {
		LFS_SEGENTRY(sup, fs, i, bp);
		seg_table[i].su_flags = sup->su_flags & ~SEGUSE_ACTIVE;
		if (preen)
			seg_table[i].su_nbytes = sup->su_nbytes;
		brelse(bp, 0);
	}

	/* Initialize Ifile entry */
	din_table[LFS_IFILE_INUM] = lfs_sb_getidaddr(fs);
	seg_table[lfs_dtosn(fs, lfs_sb_getidaddr(fs))].su_nbytes += DINOSIZE(fs);

#ifndef VERBOSE_BLOCKMAP
	bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
	blockmap = ecalloc(bmapsize, sizeof(char));
#else
	blockmap = ecalloc(maxfsblock, sizeof(ino_t));
#endif
	statemap = ecalloc(maxino, sizeof(char));
	typemap = ecalloc(maxino, sizeof(char));
	lncntp = ecalloc(maxino, sizeof(int16_t));

	if (preen) {
		n_files = lfs_sb_getnfiles(fs);
		n_blks  = lfs_sb_getdsize(fs) - lfs_sb_getbfree(fs);
		numdirs = maxino;
		inplast = 0; 
		listmax = numdirs + 10;
		inpsort = ecalloc(listmax, sizeof(struct inoinfo *));
		inphead = ecalloc(numdirs, sizeof(struct inoinfo *));
	}

	return (1);

	ckfini(0);
	return (0);
}
Ejemplo n.º 8
0
/*
 * Actually mark the segment clean.
 * Must be called with the segment lock held.
 */
int
lfs_do_segclean(struct lfs *fs, unsigned long segnum)
{
	extern int lfs_dostats;
	struct buf *bp;
	CLEANERINFO *cip;
	SEGUSE *sup;

	if (lfs_dtosn(fs, lfs_sb_getcurseg(fs)) == segnum) {
		return (EBUSY);
	}

	LFS_SEGENTRY(sup, fs, segnum, bp);
	if (sup->su_nbytes) {
		DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:"
		      " %d live bytes\n", segnum, sup->su_nbytes));
		brelse(bp, 0);
		return (EBUSY);
	}
	if (sup->su_flags & SEGUSE_ACTIVE) {
		DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:"
		      " segment is active\n", segnum));
		brelse(bp, 0);
		return (EBUSY);
	}
	if (!(sup->su_flags & SEGUSE_DIRTY)) {
		DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:"
		      " segment is already clean\n", segnum));
		brelse(bp, 0);
		return (EALREADY);
	}

	lfs_sb_addavail(fs, lfs_segtod(fs, 1));
	if (sup->su_flags & SEGUSE_SUPERBLOCK)
		lfs_sb_subavail(fs, lfs_btofsb(fs, LFS_SBPAD));
	if (lfs_sb_getversion(fs) > 1 && segnum == 0 &&
	    lfs_sb_gets0addr(fs) < lfs_btofsb(fs, LFS_LABELPAD))
		lfs_sb_subavail(fs, lfs_btofsb(fs, LFS_LABELPAD) - lfs_sb_gets0addr(fs));
	mutex_enter(&lfs_lock);
	lfs_sb_addbfree(fs, sup->su_nsums * lfs_btofsb(fs, lfs_sb_getsumsize(fs)) +
		lfs_btofsb(fs, sup->su_ninos * lfs_sb_getibsize(fs)));
	lfs_sb_subdmeta(fs, sup->su_nsums * lfs_btofsb(fs, lfs_sb_getsumsize(fs)) +
		lfs_btofsb(fs, sup->su_ninos * lfs_sb_getibsize(fs)));
	if (lfs_sb_getdmeta(fs) < 0)
		lfs_sb_setdmeta(fs, 0);
	mutex_exit(&lfs_lock);
	sup->su_flags &= ~SEGUSE_DIRTY;
	LFS_WRITESEGENTRY(sup, fs, segnum, bp);

	LFS_CLEANERINFO(cip, fs, bp);
	lfs_ci_shiftdirtytoclean(fs, cip, 1);
	lfs_sb_setnclean(fs, lfs_ci_getclean(fs, cip));
	mutex_enter(&lfs_lock);
	lfs_ci_setbfree(fs, cip, lfs_sb_getbfree(fs));
	lfs_ci_setavail(fs, cip, lfs_sb_getavail(fs)
			- fs->lfs_ravail - fs->lfs_favail);
	wakeup(&fs->lfs_availsleep);
	mutex_exit(&lfs_lock);
	(void) LFS_BWRITE_LOG(bp);

	if (lfs_dostats)
		++lfs_stats.segs_reclaimed;

	return (0);
}
Ejemplo n.º 9
0
void
pass5(void)
{
	SEGUSE *su;
	struct ubuf *bp;
	int i;
	unsigned long bb;	/* total number of used blocks (lower bound) */
	unsigned long ubb;	/* upper bound number of used blocks */
	unsigned long avail;	/* blocks available for writing */
	unsigned long dmeta;	/* blocks in segsums and inodes */
	int nclean;		/* clean segments */
	size_t labelskew;
	int diddirty;

	/*
	 * Check segment holdings against actual holdings.  Check for
	 * "clean" segments that contain live data.  If we are only
	 * rolling forward, we can't check the segment holdings, but
	 * we can still check the cleanerinfo data.
	 */
	nclean = 0;
	avail = 0;
	bb = ubb = 0;
	dmeta = 0;
	for (i = 0; i < fs->lfs_nseg; i++) {
		diddirty = 0;
		LFS_SEGENTRY(su, fs, i, bp);
		if (!preen && !(su->su_flags & SEGUSE_DIRTY) &&
		    seg_table[i].su_nbytes > 0) {
			pwarn("CLEAN SEGMENT %d CONTAINS %d BYTES\n",
			    i, seg_table[i].su_nbytes);
			if (reply("MARK SEGMENT DIRTY")) {
				su->su_flags |= SEGUSE_DIRTY;
				++diddirty;
			}
		}
		if (!preen && su->su_nbytes != seg_table[i].su_nbytes) {
			pwarn("SEGMENT %d CLAIMS %d BYTES BUT HAS %d",
			    i, su->su_nbytes, seg_table[i].su_nbytes);
			if ((int32_t)su->su_nbytes >
			    (int32_t)seg_table[i].su_nbytes)
				pwarn(" (HIGH BY %d)\n", su->su_nbytes -
				    seg_table[i].su_nbytes);
			else
				pwarn(" (LOW BY %d)\n", -su->su_nbytes +
				    seg_table[i].su_nbytes);
			if (reply("FIX")) {
				su->su_nbytes = seg_table[i].su_nbytes;
				++diddirty;
			}
		}
		if (su->su_flags & SEGUSE_DIRTY) {
			bb += btofsb(fs, su->su_nbytes +
			    su->su_nsums * fs->lfs_sumsize);
			ubb += btofsb(fs, su->su_nbytes +
			    su->su_nsums * fs->lfs_sumsize +
			    su->su_ninos * fs->lfs_ibsize);
			dmeta += btofsb(fs,
			    fs->lfs_sumsize * su->su_nsums);
			dmeta += btofsb(fs,
			    fs->lfs_ibsize * su->su_ninos);
		} else {
			nclean++;
			avail += segtod(fs, 1);
			if (su->su_flags & SEGUSE_SUPERBLOCK)
				avail -= btofsb(fs, LFS_SBPAD);
			if (i == 0 && fs->lfs_version > 1 &&
			    fs->lfs_start < btofsb(fs, LFS_LABELPAD))
				avail -= btofsb(fs, LFS_LABELPAD) -
				    fs->lfs_start;
		}
		if (diddirty)
			VOP_BWRITE(bp);
		else
			brelse(bp, 0);
	}

	/* Also may be available bytes in current seg */
	i = dtosn(fs, fs->lfs_offset);
	avail += sntod(fs, i + 1) - fs->lfs_offset;
	/* But do not count minfreesegs */
	avail -= segtod(fs, (fs->lfs_minfreeseg -
		(fs->lfs_minfreeseg / 2)));
	/* Note we may have bytes to write yet */
	avail -= btofsb(fs, locked_queue_bytes);

	if (idaddr)
		pwarn("NOTE: when using -i, expect discrepancies in dmeta,"
		      " avail, nclean, bfree\n");
	if (dmeta != fs->lfs_dmeta) {
		pwarn("DMETA GIVEN AS %d, SHOULD BE %ld\n", fs->lfs_dmeta,
		    dmeta);
		if (preen || reply("FIX")) {
			fs->lfs_dmeta = dmeta;
			sbdirty();
		}
	}
	if (avail != fs->lfs_avail) {
		pwarn("AVAIL GIVEN AS %d, SHOULD BE %ld\n", fs->lfs_avail,
		    avail);
		if (preen || reply("FIX")) {
			fs->lfs_avail = avail;
			sbdirty();
		}
	}
	if (nclean != fs->lfs_nclean) {
		pwarn("NCLEAN GIVEN AS %d, SHOULD BE %d\n", fs->lfs_nclean,
		    nclean);
		if (preen || reply("FIX")) {
			fs->lfs_nclean = nclean;
			sbdirty();
		}
	}

	labelskew = 0;
	if (fs->lfs_version > 1 &&
	    fs->lfs_start < btofsb(fs, LFS_LABELPAD))
		labelskew = btofsb(fs, LFS_LABELPAD);
	if (fs->lfs_bfree > fs->lfs_dsize - bb - labelskew ||
	    fs->lfs_bfree < fs->lfs_dsize - ubb - labelskew) {
		pwarn("BFREE GIVEN AS %d, SHOULD BE BETWEEN %ld AND %ld\n",
		    fs->lfs_bfree, (fs->lfs_dsize - ubb - labelskew),
		    fs->lfs_dsize - bb - labelskew);
		if (preen || reply("FIX")) {
			fs->lfs_bfree =
				((fs->lfs_dsize - labelskew - ubb) +
				 fs->lfs_dsize - labelskew - bb) / 2;
			sbdirty();
		}
	}
}