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
/*
 * Get a dinode of a given inum.
 * XXX combine this function with vget.
 */
struct ufs1_dinode *
ginode(ino_t ino)
{
	struct uvnode *vp;
	struct ubuf *bp;
	IFILE *ifp;

	vp = vget(fs, ino);
	if (vp == NULL)
		return NULL;

	if (din_table[ino] == 0x0) {
		LFS_IENTRY(ifp, fs, ino, bp);
		din_table[ino] = ifp->if_daddr;
		seg_table[dtosn(fs, ifp->if_daddr)].su_nbytes += DINODE1_SIZE;
		brelse(bp, 0);
	}
	return (VTOI(vp)->i_din.ffs1_din);
}
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
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();
		}
	}
}