Beispiel #1
0
static int
nandfs_cleaner_iterate_segment(struct nandfs_device *fsdev, uint64_t segno,
    struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp, int *select)
{
	struct nandfs_segment_summary *segsum;
	union nandfs_binfo *binfo;
	struct buf *bp;
	uint32_t nblocks;
	nandfs_daddr_t curr, start, end;
	int error = 0;

	nandfs_get_segment_range(fsdev, segno, &start, &end);

	DPRINTF(CLEAN, ("%s: segno %jx start %jx end %jx\n", __func__, segno,
	    start, end));

	*select = 0;

	for (curr = start; curr < end; curr += nblocks) {
		error = nandfs_dev_bread(fsdev, curr, NOCRED, 0, &bp);
		if (error) {
			brelse(bp);
			nandfs_error("%s: couldn't load segment summary of %jx: %d\n",
			    __func__, segno, error);
			return (error);
		}

		segsum = (struct nandfs_segment_summary *)bp->b_data;
		binfo = (union nandfs_binfo *)(bp->b_data + segsum->ss_bytes);

		if (!nandfs_segsum_valid(segsum)) {
			brelse(bp);
			nandfs_error("nandfs: invalid summary of segment %jx\n", segno);
			return (error);
		}

		DPRINTF(CLEAN, ("%s: %jx magic %x bytes %x nblocks %x nbinfos "
		    "%x\n", __func__, segno, segsum->ss_magic, segsum->ss_bytes,
		    segsum->ss_nblocks, segsum->ss_nbinfos));

		nandfs_cleaner_iterate_psegment(fsdev, segsum, binfo, curr,
		    vipp, bdpp);
		nblocks = segsum->ss_nblocks;
		brelse(bp);
	}

	if (error == 0)
		*select = 1;

	return (error);
}
Beispiel #2
0
static int
nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd,
    uint64_t nmembs)
{
	struct nandfs_node *dat_node;
	struct buf *bp;
	uint64_t i;
	int error;

	dat_node = nffsdev->nd_dat_node;

	VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE);

	for (i = 0; i < nmembs; i++) {
		if (!bd[i].bd_alive)
			continue;
		DPRINTF(CLEAN, ("%s: idx %jx offset %jx\n",
		    __func__, i, bd[i].bd_offset));
		if (bd[i].bd_level) {
			error = nandfs_bread_meta(dat_node, bd[i].bd_offset,
			    NULL, 0, &bp);
			if (error) {
				nandfs_error("%s: cannot read dat node "
				    "level:%d\n", __func__, bd[i].bd_level);
				brelse(bp);
				VOP_UNLOCK(NTOV(dat_node), 0);
				return (error);
			}
			nandfs_dirty_buf_meta(bp, 1);
			nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1);
		} else {
			error = nandfs_bread(dat_node, bd[i].bd_offset, NULL,
			    0, &bp);
			if (error) {
				nandfs_error("%s: cannot read dat node\n",
				    __func__);
				brelse(bp);
				VOP_UNLOCK(NTOV(dat_node), 0);
				return (error);
			}
			nandfs_dirty_buf(bp, 1);
		}
		DPRINTF(CLEAN, ("%s: bp: %p\n", __func__, bp));
	}

	VOP_UNLOCK(NTOV(dat_node), 0);

	return (0);
}
Beispiel #3
0
/* Update block count of segment */
int
nandfs_update_segment(struct nandfs_device *fsdev, uint64_t seg, uint32_t nblks)
{
	struct nandfs_node *su_node;
	struct nandfs_segment_usage *su_usage;
	struct buf *bp;
	uint64_t blk, offset;
	int error;

	su_node = fsdev->nd_su_node;
	ASSERT_VOP_LOCKED(NTOV(su_node), __func__);

	nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset);

	error = nandfs_bread(su_node, blk, NOCRED, 0, &bp);
	if (error) {
		nandfs_error("%s: read block:%jx to update\n",
		    __func__, blk);
		brelse(bp);
		return (error);
	}

	su_usage = SU_USAGE_OFF(bp, offset);
	su_usage->su_lastmod = fsdev->nd_ts.tv_sec;
	su_usage->su_flags = NANDFS_SEGMENT_USAGE_DIRTY;
	su_usage->su_nblocks += nblks;

	DPRINTF(SEG, ("%s: seg:%#jx inc:%#x cur:%#x\n",  __func__,
	    (uintmax_t)seg, nblks, su_usage->su_nblocks));

	nandfs_dirty_buf(bp, 1);

	return (0);
}
Beispiel #4
0
int
nandfs_node_destroy(struct nandfs_node *node)
{
	struct nandfs_alloc_request req;
	struct nandfsmount *nmp;
	struct nandfs_mdt *mdt;
	struct nandfs_node *ifile;
	struct vnode *vp;
	int error = 0;

	nmp = node->nn_nmp;
	req.entrynum = node->nn_ino;
	mdt = &nmp->nm_nandfsdev->nd_ifile_mdt;
	ifile = nmp->nm_ifile_node;
	vp = NTOV(ifile);

	DPRINTF(IFILE, ("%s: destroy node: %p ino: %#jx\n",
	    __func__, node, (uintmax_t)node->nn_ino));
	VOP_LOCK(vp, LK_EXCLUSIVE);

	error = nandfs_find_entry(mdt, ifile, &req);
	if (error) {
		nandfs_error("%s: finding entry error:%d node %p(%jx)",
		    __func__, error, node, node->nn_ino);
		VOP_UNLOCK(vp, 0);
		return (error);
	}

	nandfs_inode_destroy(&node->nn_inode);

	error = nandfs_free_entry(mdt, &req);
	if (error) {
		nandfs_error("%s: freing entry error:%d node %p(%jx)",
		    __func__, error, node, node->nn_ino);
		VOP_UNLOCK(vp, 0);
		return (error);
	}

	VOP_UNLOCK(vp, 0);
	DPRINTF(IFILE, ("%s: freed node %p ino %#jx\n",
	    __func__, node, (uintmax_t)node->nn_ino));
	return (error);
}
int
nandfs_bmap_dirty_blocks(struct nandfs_node *node, struct buf *bp, int force)
{
	int error;

	error = bmap_dirty_meta(node, bp->b_lblkno, force);
	if (error)
		nandfs_error("%s: cannot dirty buffer %p\n",
		    __func__, bp);

	return (error);
}
Beispiel #6
0
int
nandfs_init_dir(struct vnode *dvp, uint64_t ino, uint64_t parent_ino)
{

	if (nandfs_add_dirent(dvp, parent_ino, "..", 2, DT_DIR) ||
	    nandfs_add_dirent(dvp, ino, ".", 1, DT_DIR)) {
		nandfs_error("%s: cannot initialize dir ino:%jd(pino:%jd)\n",
		    __func__, ino, parent_ino);
		return (-1);
	}
	return (0);
}
Beispiel #7
0
static int
nandfs_cleaner_choose_segment(struct nandfs_device *fsdev, uint64_t **segpp,
    uint64_t nsegs, uint64_t *rseg)
{
	struct nandfs_suinfo *suinfo;
	uint64_t i, ssegs;
	int error;

	suinfo = malloc(sizeof(*suinfo) * nsegs, M_NANDFSTEMP,
	    M_ZERO | M_WAITOK);

	if (*rseg >= fsdev->nd_fsdata.f_nsegments)
		*rseg = 0;

retry:
	error = nandfs_get_segment_info_filter(fsdev, suinfo, nsegs, *rseg,
	    &ssegs, NANDFS_SEGMENT_USAGE_DIRTY,
	    NANDFS_SEGMENT_USAGE_ACTIVE | NANDFS_SEGMENT_USAGE_ERROR |
	    NANDFS_SEGMENT_USAGE_GC);
	if (error) {
		nandfs_error("%s:%d", __FILE__, __LINE__);
		goto out;
	}

	if (ssegs == 0 && *rseg != 0) {
		*rseg = 0;
		goto retry;
	}

	print_suinfo(suinfo, ssegs);

	for (i = 0; i < ssegs; i++) {
		(**segpp) = suinfo[i].nsi_num;
		(*segpp)++;
	}

	*rseg = suinfo[i - 1].nsi_num + 1;
out:
	free(suinfo, M_NANDFSTEMP);

	return (error);
}
int
nandfs_bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk,
    nandfs_daddr_t *vblk)
{
	int error = 0;

	if (node->nn_ino == NANDFS_GC_INO && lblk >= 0)
		*vblk = lblk;
	else
		error = bmap_lookup(node, lblk, vblk);

	DPRINTF(TRANSLATE, ("%s: error %d ino %#jx lblocknr %#jx -> %#jx\n",
	    __func__, error, (uintmax_t)node->nn_ino, (uintmax_t)lblk,
	    (uintmax_t)*vblk));

	if (error)
		nandfs_error("%s: returned %d", __func__, error);

	return (error);
}
Beispiel #9
0
/*
 * Make buffer dirty, it will be updated soon but first it need to be
 * gathered by syncer.
 */
int
nandfs_touch_segment(struct nandfs_device *fsdev, uint64_t seg)
{
	struct nandfs_node *su_node;
	struct buf *bp;
	uint64_t blk, offset;
	int error;

	su_node = fsdev->nd_su_node;
	ASSERT_VOP_LOCKED(NTOV(su_node), __func__);

	nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset);

	error = nandfs_bread(su_node, blk, NOCRED, 0, &bp);
	if (error) {
		brelse(bp);
		nandfs_error("%s: cannot preallocate new segment\n", __func__);
		return (error);
	} else
		nandfs_dirty_buf(bp, 1);

	DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg));
	return (error);
}
Beispiel #10
0
int
nandfs_bmap_update_block(struct nandfs_node *node, struct buf *bp,
    nandfs_lbn_t blknr)
{
	nandfs_lbn_t lblk;
	int error;

	lblk = bp->b_lblkno;
	nandfs_vblk_set(bp, blknr);

	DPRINTF(BMAP, ("%s: node: %p ino: %#jx bp: %p lblk: %#jx blk: %#jx\n",
	    __func__, node, (uintmax_t)node->nn_ino, bp,
	    (uintmax_t)lblk, (uintmax_t)blknr));

	error = nandfs_bmap_update_mapping(node, lblk, blknr);
	if (error) {
		nandfs_error("%s: cannot update lblk:%jx to blk:%jx for "
		    "node:%p, error:%d\n", __func__, (uintmax_t)lblk,
		    (uintmax_t)blknr, node, error);
		return (error);
	}

	return (error);
}
Beispiel #11
0
/* Alloc new segment */
int
nandfs_alloc_segment(struct nandfs_device *fsdev, uint64_t *seg)
{
	struct nandfs_node *su_node;
	struct nandfs_sufile_header *su_header;
	struct nandfs_segment_usage *su_usage;
	struct buf *bp_header, *bp;
	uint64_t blk, vblk, offset, i, rest, nsegments;
	uint16_t seg_size;
	int error, found;

	seg_size = fsdev->nd_fsdata.f_segment_usage_size;
	nsegments = fsdev->nd_fsdata.f_nsegments;

	su_node = fsdev->nd_su_node;
	ASSERT_VOP_LOCKED(NTOV(su_node), __func__);

	/* Read header buffer */
	error = nandfs_bread(su_node, 0, NOCRED, 0, &bp_header);
	if (error) {
		brelse(bp_header);
		return (error);
	}

	su_header = (struct nandfs_sufile_header *)bp_header->b_data;

	/* Get last allocated segment */
	i = su_header->sh_last_alloc + 1;

	found = 0;
	bp = NULL;
	while (!found) {
		nandfs_seg_usage_blk_offset(fsdev, i, &blk, &offset);
		if(blk != 0) {
			error = nandfs_bmap_lookup(su_node, blk, &vblk);
			if (error) {
				nandfs_error("%s: cannot find vblk for blk "
				    "blk:%jx\n", __func__, blk);
				return (error);
			}
			if (vblk)
				error = nandfs_bread(su_node, blk, NOCRED, 0,
				    &bp);
			else
				error = nandfs_bcreate(su_node, blk, NOCRED, 0,
				    &bp);
			if (error) {
				nandfs_error("%s: cannot create/read "
				    "vblk:%jx\n", __func__, vblk);
				if (bp)
					brelse(bp);
				return (error);
			}

			su_usage = SU_USAGE_OFF(bp, offset);
		} else {
			su_usage = SU_USAGE_OFF(bp_header, offset);
			bp = bp_header;
		}

		rest = (fsdev->nd_blocksize - offset) / seg_size;
		/* Go through all su usage in block */
		while (rest) {
			/* When last check start from beggining */
			if (i == nsegments)
				break;

			if (!su_usage->su_flags) {
				su_usage->su_flags = 1;
				found = 1;
				break;
			}
			su_usage++;
			i++;

			/* If all checked return error */
			if (i == su_header->sh_last_alloc) {
				DPRINTF(SEG, ("%s: cannot allocate segment \n",
				    __func__));
				brelse(bp_header);
				if (blk != 0)
					brelse(bp);
				return (1);
			}
			rest--;
		}
		if (!found) {
			/* Otherwise read another block */
			if (blk != 0)
				brelse(bp);
			if (i == nsegments) {
				blk = 0;
				i = 0;
			} else
				blk++;
			offset = 0;
		}
	}

	if (found) {
		*seg = i;
		su_header->sh_last_alloc = i;
		su_header->sh_ncleansegs--;
		su_header->sh_ndirtysegs++;

		fsdev->nd_super.s_free_blocks_count = su_header->sh_ncleansegs *
		    fsdev->nd_fsdata.f_blocks_per_segment;
		fsdev->nd_clean_segs--;

		/*
		 * It is mostly called from syncer() so we want to force
		 * making buf dirty.
		 */
		error = nandfs_dirty_buf(bp_header, 1);
		if (error) {
			if (bp && bp != bp_header)
				brelse(bp);
			return (error);
		}
		if (bp && bp != bp_header)
			nandfs_dirty_buf(bp, 1);

		DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)i));

		return (0);
	}

	DPRINTF(SEG, ("%s: failed\n", __func__));

	return (1);
}
Beispiel #12
0
int
nandfs_vblock_alloc(struct nandfs_device *nandfsdev, nandfs_daddr_t *vblock)
{
	struct nandfs_node *dat;
	struct nandfs_mdt *mdt;
	struct nandfs_alloc_request req;
	struct nandfs_dat_entry *dat_entry;
	uint64_t start;
	uint32_t entry;
	int locked, error;

	dat = nandfsdev->nd_dat_node;
	mdt = &nandfsdev->nd_dat_mdt;
	start = nandfsdev->nd_last_cno + 1;

	locked = NANDFS_VOP_ISLOCKED(NTOV(dat));
	if (!locked)
		VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
	req.entrynum = 0;

	/* Alloc vblock number */
	error = nandfs_find_free_entry(mdt, dat, &req);
	if (error) {
		nandfs_error("%s: cannot find free vblk entry\n",
		    __func__);
		if (!locked)
			VOP_UNLOCK(NTOV(dat), 0);
		return (error);
	}

	/* Read/create buffer */
	error = nandfs_get_entry_block(mdt, dat, &req, &entry, 1);
	if (error) {
		nandfs_error("%s: cannot get free vblk entry\n",
		    __func__);
		nandfs_abort_entry(&req);
		if (!locked)
			VOP_UNLOCK(NTOV(dat), 0);
		return (error);
	}

	/* Fill out vblock data */
	dat_entry = (struct nandfs_dat_entry *) req.bp_entry->b_data;
	dat_entry[entry].de_start = start;
	dat_entry[entry].de_end = UINTMAX_MAX;
	dat_entry[entry].de_blocknr = 0;

	/* Commit allocation */
	error = nandfs_alloc_entry(mdt, &req);
	if (error) {
		nandfs_error("%s: cannot get free vblk entry\n",
		    __func__);
		if (!locked)
			VOP_UNLOCK(NTOV(dat), 0);
		return (error);
	}

	/* Return allocated vblock */
	*vblock = req.entrynum;
	DPRINTF(DAT, ("%s: allocated vblock %#jx\n",
	    __func__, (uintmax_t)*vblock));

	if (!locked)
		VOP_UNLOCK(NTOV(dat), 0);
	return (error);
}
Beispiel #13
0
int
bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk,
    nandfs_daddr_t vblk)
{
	struct nandfs_inode *ip;
	struct nandfs_indir a[NIADDR+1], *ap;
	struct buf *bp;
	nandfs_daddr_t daddr;
	int error;
	int num, *nump, i;

	DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx\n", __func__, node, lblk,
	    vblk));

	ip = &node->nn_inode;

	ap = a;
	nump = &num;

	error = bmap_getlbns(node, lblk, ap, nump);
	if (error)
		return (error);

	DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx got num=%d\n", __func__,
	    node, lblk, vblk, num));

	if (num == 0) {
		DPRINTF(BMAP, ("%s: node %p lblk=%jx direct block\n", __func__,
		    node, lblk));
		ip->i_db[lblk] = vblk;
		return (0);
	}

	DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block level %d\n",
	    __func__, node, lblk, ap->in_off));

	if (num == 1) {
		DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block: inserting "
		    "%jx as vblk for indirect block %d\n", __func__, node,
		    lblk, vblk, ap->in_off));
		ip->i_ib[ap->in_off] = vblk;
		return (0);
	}

	bp = NULL;
	daddr = ip->i_ib[a[0].in_off];
	for (i = 1; i < num; i++) {
		if (bp)
			brelse(bp);
		if (daddr == 0) {
			DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx create "
			    "block %jx %d\n", __func__, node, lblk, vblk,
			    a[i].in_lbn, a[i].in_off));
			error = nandfs_bcreate_meta(node, a[i].in_lbn, NOCRED,
			    0, &bp);
			if (error)
				return (error);
		} else {
			DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx read "
			    "block %jx %d\n", __func__, node, daddr, vblk,
			    a[i].in_lbn, a[i].in_off));
			error = nandfs_bread_meta(node, a[i].in_lbn, NOCRED, 0, &bp);
			if (error) {
				brelse(bp);
				return (error);
			}
		}
		daddr = ((nandfs_daddr_t *)bp->b_data)[a[i].in_off];
	}
	i--;

	DPRINTF(BMAP,
	    ("%s: bmap node %p lblk=%jx vblk=%jx inserting vblk level %d at "
	    "offset %d at %jx\n", __func__, node, lblk, vblk, i, a[i].in_off,
	    daddr));

	if (!bp) {
		nandfs_error("%s: cannot find indirect block\n", __func__);
		return (-1);
	}
	((nandfs_daddr_t *)bp->b_data)[a[i].in_off] = vblk;

	error = nandfs_dirty_buf_meta(bp, 0);
	if (error) {
		nandfs_warning("%s: dirty failed buf: %p\n", __func__, bp);
		return (error);
	}
	DPRINTF(BMAP, ("%s: exiting node %p lblk=%jx vblk=%jx\n", __func__,
	    node, lblk, vblk));

	return (error);
}
Beispiel #14
0
int
bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t lastblk,
    nandfs_lbn_t todo)
{
	struct nandfs_inode *ip;
	struct nandfs_indir a[NIADDR + 1], f[NIADDR], *ap;
	nandfs_daddr_t indir_lbn[NIADDR];
	nandfs_daddr_t *copy;
	int error, level;
	nandfs_lbn_t left, tosub;
	struct nandfs_device *fsdev;
	int cleaned, i;
	int num, *nump;

	DPRINTF(BMAP, ("%s: node %p lastblk %jx truncating by %jx\n", __func__,
	    node, lastblk, todo));

	ip = &node->nn_inode;
	fsdev = node->nn_nandfsdev;

	ap = a;
	nump = &num;

	error = bmap_getlbns(node, lastblk, ap, nump);
	if (error)
		return (error);

	indir_lbn[SINGLE] = -NDADDR;
	indir_lbn[DOUBLE] = indir_lbn[SINGLE] - MNINDIR(fsdev) - 1;
	indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - MNINDIR(fsdev)
	    * MNINDIR(fsdev) - 1;

	for (i = 0; i < NIADDR; i++) {
		f[i].in_off = MNINDIR(fsdev) - 1;
		f[i].in_lbn = 0xdeadbeef;
	}

	left = todo;

#ifdef DEBUG
	a[num].in_off = -1;
#endif

	ap++;
	num -= 2;

	if (num < 0)
		goto direct;

	copy = malloc(MNINDIR(fsdev) * sizeof(nandfs_daddr_t) * (num + 1),
	    M_NANDFSTEMP, M_WAITOK);

	for (level = num; level >= SINGLE && left > 0; level--) {
		cleaned = 0;

		if (ip->i_ib[level] == 0) {
			tosub = blocks_inside(fsdev, level, ap);
			if (tosub > left)
				left = 0;
			else
				left -= tosub;
		} else {
			if (ap == f)
				ap->in_lbn = indir_lbn[level];
			error = bmap_truncate_indirect(node, level, &left,
			    &cleaned, ap, f, copy);
			if (error) {
				nandfs_error("%s: error %d when truncate "
				    "at level %d\n", __func__, error, level);
				return (error);
			}
		}

		if (cleaned) {
			nandfs_vblock_end(fsdev, ip->i_ib[level]);
			ip->i_ib[level] = 0;
		}

		ap = f;
	}

	free(copy, M_NANDFSTEMP);

direct:
	if (num < 0)
		i = lastblk;
	else
		i = NDADDR - 1;

	for (; i >= 0 && left > 0; i--) {
		if (ip->i_db[i] != 0) {
			error = nandfs_bdestroy(node, ip->i_db[i]);
			if (error) {
				nandfs_error("%s: cannot destroy "
				    "block %jx, error %d\n", __func__,
				    (uintmax_t)ip->i_db[i], error);
				return (error);
			}
			ip->i_db[i] = 0;
		}

		left--;
	}

	KASSERT(left == 0,
	    ("truncated wrong number of blocks (%jd should be 0)", left));

	return (error);
}
Beispiel #15
0
static int
nandfs_cleaner_clean_segments(struct nandfs_device *nffsdev,
    struct nandfs_vinfo *vinfo, uint32_t nvinfo,
    struct nandfs_period *pd, uint32_t npd,
    struct nandfs_bdesc *bdesc, uint32_t nbdesc,
    uint64_t *segments, uint32_t nsegs)
{
	struct nandfs_node *gc;
	struct buf *bp;
	uint32_t i;
	int error = 0;

	gc = nffsdev->nd_gc_node;

	DPRINTF(CLEAN, ("%s: enter\n", __func__));

	VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
	for (i = 0; i < nvinfo; i++) {
		if (!vinfo[i].nvi_alive)
			continue;
		DPRINTF(CLEAN, ("%s: read vblknr:%#jx blk:%#jx\n",
		    __func__, (uintmax_t)vinfo[i].nvi_vblocknr,
		    (uintmax_t)vinfo[i].nvi_blocknr));
		error = nandfs_bread(nffsdev->nd_gc_node, vinfo[i].nvi_blocknr,
		    NULL, 0, &bp);
		if (error) {
			nandfs_error("%s:%d", __FILE__, __LINE__);
			VOP_UNLOCK(NTOV(gc), 0);
			goto out;
		}
		nandfs_vblk_set(bp, vinfo[i].nvi_vblocknr);
		nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED);
		nandfs_dirty_buf(bp, 1);
	}
	VOP_UNLOCK(NTOV(gc), 0);

	/* Delete checkpoints */
	for (i = 0; i < npd; i++) {
		DPRINTF(CLEAN, ("delete checkpoint: %jx\n",
		    (uintmax_t)pd[i].p_start));
		error = nandfs_delete_cp(nffsdev->nd_cp_node, pd[i].p_start,
		    pd[i].p_end);
		if (error) {
			nandfs_error("%s:%d", __FILE__, __LINE__);
			goto out;
		}
	}

	/* Update vblocks */
	for (i = 0; i < nvinfo; i++) {
		if (vinfo[i].nvi_alive)
			continue;
		DPRINTF(CLEAN, ("freeing vblknr: %jx\n", vinfo[i].nvi_vblocknr));
		error = nandfs_vblock_free(nffsdev, vinfo[i].nvi_vblocknr);
		if (error) {
			nandfs_error("%s:%d", __FILE__, __LINE__);
			goto out;
		}
	}

	error = nandfs_process_bdesc(nffsdev, bdesc, nbdesc);
	if (error) {
		nandfs_error("%s:%d", __FILE__, __LINE__);
		goto out;
	}

	/* Add segments to clean */
	if (nffsdev->nd_free_count) {
		nffsdev->nd_free_base = realloc(nffsdev->nd_free_base,
		    (nffsdev->nd_free_count + nsegs) * sizeof(uint64_t),
		    M_NANDFSTEMP, M_WAITOK | M_ZERO);
		memcpy(&nffsdev->nd_free_base[nffsdev->nd_free_count], segments,
		    nsegs * sizeof(uint64_t));
		nffsdev->nd_free_count += nsegs;
	} else {
		nffsdev->nd_free_base = malloc(nsegs * sizeof(uint64_t),
		    M_NANDFSTEMP, M_WAITOK|M_ZERO);
		memcpy(nffsdev->nd_free_base, segments,
		    nsegs * sizeof(uint64_t));
		nffsdev->nd_free_count = nsegs;
	}

out:

	DPRINTF(CLEAN, ("%s: exit error %d\n", __func__, error));

	return (error);
}
Beispiel #16
0
static int
nandfs_cleaner_body(struct nandfs_device *fsdev, uint64_t *rseg)
{
	struct nandfs_vinfo *vinfo, *vip, *vipi;
	struct nandfs_bdesc *bdesc, *bdp, *bdpi;
	struct nandfs_cpstat cpstat;
	struct nandfs_cpinfo *cpinfo = NULL;
	uint64_t *segnums, *segp;
	int select, selected;
	int error = 0;
	int nsegs;
	int i;

	nsegs = nandfs_cleaner_segments;

	vip = vinfo = malloc(sizeof(*vinfo) *
	    fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP,
	    M_ZERO | M_WAITOK);
	bdp = bdesc = malloc(sizeof(*bdesc) *
	    fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP,
	    M_ZERO | M_WAITOK);
	segp = segnums = malloc(sizeof(*segnums) * nsegs, M_NANDFSTEMP,
	    M_WAITOK);

	error = nandfs_cleaner_choose_segment(fsdev, &segp, nsegs, rseg);
	if (error) {
		nandfs_error("%s:%d", __FILE__, __LINE__);
		goto out;
	}

	if (segnums == segp)
		goto out;

	selected = 0;
	for (i = 0; i < segp - segnums; i++) {
		error = nandfs_cleaner_iterate_segment(fsdev, segnums[i], &vip,
		    &bdp, &select);
		if (error) {
			/*
			 * XXX deselect (see below)?
			 */
			goto out;
		}
		if (!select)
			segnums[i] = NANDFS_NOSEGMENT;
		else {
			error = nandfs_markgc_segment(fsdev, segnums[i]);
			if (error) {
				nandfs_error("%s:%d\n", __FILE__, __LINE__);
				goto out;
			}
			selected++;
		}
	}

	if (selected == 0) {
		MPASS(vinfo == vip);
		MPASS(bdesc == bdp);
		goto out;
	}

	error = nandfs_get_cpstat(fsdev->nd_cp_node, &cpstat);
	if (error) {
		nandfs_error("%s:%d\n", __FILE__, __LINE__);
		goto out;
	}

	if (cpstat.ncp_nss != 0) {
		cpinfo = malloc(sizeof(struct nandfs_cpinfo) * cpstat.ncp_nss,
		    M_NANDFSTEMP, M_WAITOK);
		error = nandfs_get_cpinfo(fsdev->nd_cp_node, 1, NANDFS_SNAPSHOT,
		    cpinfo, cpstat.ncp_nss, NULL);
		if (error) {
			nandfs_error("%s:%d\n", __FILE__, __LINE__);
			goto out_locked;
		}
	}

	NANDFS_WRITELOCK(fsdev);
	DPRINTF(CLEAN, ("%s: got lock\n", __func__));

	error = nandfs_get_dat_vinfo(fsdev, vinfo, vip - vinfo);
	if (error) {
		nandfs_error("%s:%d\n", __FILE__, __LINE__);
		goto out_locked;
	}

	nandfs_cleaner_vinfo_mark_alive(fsdev, vinfo, vip - vinfo, cpinfo,
	    cpstat.ncp_nss);

	error = nandfs_get_dat_bdescs(fsdev, bdesc, bdp - bdesc);
	if (error) {
		nandfs_error("%s:%d\n", __FILE__, __LINE__);
		goto out_locked;
	}

	nandfs_cleaner_bdesc_mark_alive(fsdev, bdesc, bdp - bdesc);

	DPRINTF(CLEAN, ("got:\n"));
	for (vipi = vinfo; vipi < vip; vipi++) {
		DPRINTF(CLEAN, ("v ino %jx vblocknr %jx start %jx end %jx "
		    "alive %d\n", vipi->nvi_ino, vipi->nvi_vblocknr,
		    vipi->nvi_start, vipi->nvi_end, vipi->nvi_alive));
	}
	for (bdpi = bdesc; bdpi < bdp; bdpi++) {
		DPRINTF(CLEAN, ("b oblocknr %jx blocknr %jx offset %jx "
		    "alive %d\n", bdpi->bd_oblocknr, bdpi->bd_blocknr,
		    bdpi->bd_offset, bdpi->bd_alive));
	}
	DPRINTF(CLEAN, ("end list\n"));

	error = nandfs_cleaner_clean_segments(fsdev, vinfo, vip - vinfo, NULL,
	    0, bdesc, bdp - bdesc, segnums, segp - segnums);
	if (error)
		nandfs_error("%s:%d\n", __FILE__, __LINE__);

out_locked:
	NANDFS_WRITEUNLOCK(fsdev);
out:
	free(cpinfo, M_NANDFSTEMP);
	free(segnums, M_NANDFSTEMP);
	free(bdesc, M_NANDFSTEMP);
	free(vinfo, M_NANDFSTEMP);

	return (error);
}
Beispiel #17
0
int
nandfs_remove_dirent(struct vnode *dvp, struct nandfs_node *node,
    struct componentname *cnp)
{
	struct nandfs_node *dir_node;
	struct nandfs_dir_entry *dirent, *pdirent;
	struct buf *bp;
	uint64_t filesize, blocknr, ino, offset;
	uint32_t blocksize, limit, off;
	uint16_t newsize;
	uint8_t *pos;
	int error, found;

	dir_node = VTON(dvp);
	filesize = dir_node->nn_inode.i_size;
	if (!filesize)
		return (0);

	if (node) {
		offset = node->nn_diroff;
		ino = node->nn_ino;
	} else {
		offset = dir_node->nn_diroff;
		ino = NANDFS_WHT_INO;
	}

	dirent = pdirent = NULL;
	blocksize = dir_node->nn_nandfsdev->nd_blocksize;
	blocknr = offset / blocksize;

	DPRINTF(LOOKUP, ("rm direntry dvp %p node %p ino %#jx at off %#jx\n",
	    dvp, node, (uintmax_t)ino, (uintmax_t)offset));

	error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp);
	if (error) {
		brelse(bp);
		return (error);
	}

	pos = bp->b_data;
	off = 0;
	found = 0;
	limit = offset % blocksize;
	pdirent = (struct nandfs_dir_entry *) bp->b_data;
	while (off <= limit) {
		dirent = (struct nandfs_dir_entry *) (pos + off);

		if ((off == limit) &&
		    (dirent->inode == ino)) {
			found = 1;
			break;
		}
		if (dirent->inode != 0)
			pdirent = dirent;
		off += dirent->rec_len;
	}

	if (!found) {
		nandfs_error("cannot find entry to remove");
		brelse(bp);
		return (error);
	}
	DPRINTF(LOOKUP,
	    ("rm dirent ino %#jx at %#x with size %#x\n",
	    (uintmax_t)dirent->inode, off, dirent->rec_len));

	newsize = (uintptr_t)dirent - (uintptr_t)pdirent;
	newsize += dirent->rec_len;
	pdirent->rec_len = newsize;
	dirent->inode = 0;
	error = nandfs_dirty_buf(bp, 0);
	if (error)
		return (error);

	dir_node->nn_flags |= IN_CHANGE | IN_UPDATE;
	/* If last one modify filesize */
	if ((offset + NANDFS_DIR_REC_LEN(dirent->name_len)) == filesize) {
		filesize = blocknr * blocksize +
		    ((uintptr_t)pdirent - (uintptr_t)pos) +
		    NANDFS_DIR_REC_LEN(pdirent->name_len);
		dir_node->nn_inode.i_size = filesize;
	}

	return (0);
}