Ejemplo n.º 1
0
int
nandfs_get_entry_block(struct nandfs_mdt *mdt, struct nandfs_node *node,
    struct nandfs_alloc_request *req, uint32_t *entry, int create)
{
	struct buf *bp;
	nandfs_lbn_t blocknr;
	int	error;

	/* Find buffer number for given entry */
	nandfs_mdt_trans(mdt, req->entrynum, &blocknr, entry);
	DPRINTF(ALLOC, ("%s: ino %#jx entrynum:%#jx block:%#jx entry:%x\n",
	    __func__, (uintmax_t)node->nn_ino, (uintmax_t)req->entrynum,
	    (uintmax_t)blocknr, *entry));

	/* Read entry block or create if 'create' parameter is not zero */
	bp = NULL;

	if (blocknr < node->nn_inode.i_blocks)
		error = nandfs_bread(node, blocknr, NOCRED, 0, &bp);
	else if (create)
		error = nandfs_bcreate(node, blocknr, NOCRED, 0, &bp);
	else
		error = E2BIG;

	if (error) {
		DPRINTF(ALLOC, ("%s: ino %#jx block %#jx entry %x error %d\n",
		    __func__, (uintmax_t)node->nn_ino, (uintmax_t)blocknr,
		    *entry, error));
		if (bp)
			brelse(bp);
		return (error);
	}

	MPASS(nandfs_vblk_get(bp) != 0 || node->nn_ino == NANDFS_DAT_INO);

	req->bp_entry = bp;
	return (0);
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
0
int
nandfs_add_dirent(struct vnode *dvp, uint64_t ino, char *nameptr, long namelen,
    uint8_t type)
{
	struct nandfs_node *dir_node = VTON(dvp);
	struct nandfs_dir_entry *dirent, *pdirent;
	uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize;
	uint64_t filesize = dir_node->nn_inode.i_size;
	uint64_t inode_blks = dir_node->nn_inode.i_blocks;
	uint32_t off, rest;
	uint8_t *pos;
	struct buf *bp;
	int error;

	pdirent = NULL;
	bp = NULL;
	if (inode_blks) {
		error = nandfs_bread(dir_node, inode_blks - 1, NOCRED, 0, &bp);
		if (error) {
			brelse(bp);
			return (error);
		}

		pos = bp->b_data;
		off = 0;
		while (off < blocksize) {
			pdirent = (struct nandfs_dir_entry *) (pos + off);
			if (!pdirent->rec_len) {
				pdirent = NULL;
				break;
			}
			off += pdirent->rec_len;
		}

		if (pdirent)
			rest = pdirent->rec_len -
			    NANDFS_DIR_REC_LEN(pdirent->name_len);
		else
			rest = blocksize;

		if (rest < NANDFS_DIR_REC_LEN(namelen)) {
			/* Do not update pdirent as new block is created */
			pdirent = NULL;
			brelse(bp);
			/* Set to NULL to create new */
			bp = NULL;
			filesize += rest;
		}
	}

	/* If no bp found create new */
	if (!bp) {
		error = nandfs_bcreate(dir_node, inode_blks, NOCRED, 0, &bp);
		if (error)
			return (error);
		off = 0;
		pos = bp->b_data;
	}

	/* Modify pdirent if exists */
	if (pdirent) {
		DPRINTF(LOOKUP, ("modify pdirent %p\n", pdirent));
		/* modify last de */
		off -= pdirent->rec_len;
		pdirent->rec_len =
		    NANDFS_DIR_REC_LEN(pdirent->name_len);
		off += pdirent->rec_len;
	}

	/* Create new dirent */
	dirent = (struct nandfs_dir_entry *) (pos + off);
	dirent->rec_len = blocksize - off;
	dirent->inode = ino;
	dirent->name_len = namelen;
	memset(dirent->name, 0, NANDFS_DIR_NAME_LEN(namelen));
	memcpy(dirent->name, nameptr, namelen);
	dirent->file_type = type;

	filesize += NANDFS_DIR_REC_LEN(dirent->name_len);

	DPRINTF(LOOKUP, ("create dir_entry '%.*s' at %p with size %x "
	    "new filesize: %jx\n",
	    (int)namelen, dirent->name, dirent, dirent->rec_len,
	    (uintmax_t)filesize));

	error = nandfs_dirty_buf(bp, 0);
	if (error)
		return (error);

	dir_node->nn_inode.i_size = filesize;
	dir_node->nn_flags |= IN_CHANGE | IN_UPDATE;
	vnode_pager_setsize(dvp, filesize);

	return (0);
}
Ejemplo n.º 4
0
int
nandfs_find_free_entry(struct nandfs_mdt *mdt, struct nandfs_node *node,
    struct nandfs_alloc_request *req)
{
	nandfs_daddr_t desc, group, maxgroup, maxdesc, pos = 0;
	nandfs_daddr_t start_group, start_desc;
	nandfs_daddr_t desc_block, group_block;
	nandfs_daddr_t file_blocks;
	struct nandfs_block_group_desc *descriptors;
	struct buf *bp, *bp2;
	uint32_t *mask, i, mcount, msize;
	int error;

	file_blocks = node->nn_inode.i_blocks;
	maxgroup = 0x100000000ull / mdt->entries_per_group;
	maxdesc = maxgroup / mdt->groups_per_desc_block;
	start_group = req->entrynum / mdt->entries_per_group;
	start_desc = start_group / mdt->groups_per_desc_block;

	bp = bp2 = NULL;
restart:
	for (desc = start_desc; desc < maxdesc; desc++) {
		nandfs_get_desc_block_nr(mdt, desc, &desc_block);

		if (bp)
			brelse(bp);
		if (desc_block < file_blocks) {
			error = nandfs_bread(node, desc_block, NOCRED, 0, &bp);
			if (error) {
				brelse(bp);
				return (error);
			}
		} else {
			error = nandfs_bcreate(node, desc_block, NOCRED, 0,
			    &bp);
			if (error)
				return (error);
			file_blocks++;
			init_desc_block(mdt, bp->b_data);
		}

		descriptors = (struct nandfs_block_group_desc *) bp->b_data;
		for (group = start_group; group < mdt->groups_per_desc_block;
		    group++) {
			if (descriptors[group].bg_nfrees > 0) {
				nandfs_get_group_block_nr(mdt, group,
				    &group_block);

				if (bp2)
					brelse(bp2);
				if (group_block < file_blocks) {
					error = nandfs_bread(node, group_block,
					    NOCRED, 0, &bp2);
					if (error) {
						brelse(bp);
						return (error);
					}
				} else {
					error = nandfs_bcreate(node,
					    group_block, NOCRED, 0, &bp2);
					if (error)
						return (error);
					file_blocks++;
				}
				mask = (uint32_t *)bp2->b_data;
				msize = (sizeof(uint32_t) * __CHAR_BIT);
				mcount = mdt->entries_per_group / msize;
				for (i = 0; i < mcount; i++) {
					if (mask[i] == UINT32_MAX)
						continue;

					pos = ffs(~mask[i]) - 1;
					pos += (msize * i);
					pos += (group * mdt->entries_per_group);
					pos += desc * group *
					    mdt->groups_per_desc_block *
					    mdt->entries_per_group;
					goto found;
				}
			}
		}
		start_group = 0;
	}

	if (start_desc != 0) {
		maxdesc = start_desc;
		start_desc = 0;
		req->entrynum = 0;
		goto restart;
	}

	return (ENOENT);

found:
	req->entrynum = pos;
	req->bp_desc = bp;
	req->bp_bitmap = bp2;
	DPRINTF(ALLOC, ("%s: desc: %p bitmap: %p entry: %#jx\n",
	    __func__, req->bp_desc, req->bp_bitmap, (uintmax_t)pos));

	return (0);
}