Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3a7abf0 authored by Ryusuke Konishi's avatar Ryusuke Konishi
Browse files

nilfs2: support contiguous lookup of blocks



Although get_block() callback function can return extent of contiguous
blocks with bh->b_size, nilfs_get_block() function did not support
this feature.

This adds contiguous lookup feature to the block mapping codes of
nilfs, and allows the nilfs_get_blocks() function to return the extent
information by applying the feature.

Signed-off-by: default avatarRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
parent fa032744
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@
#include "dat.h"
#include "alloc.h"

static struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap)
struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap)
{
	return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode));
}
@@ -58,6 +58,16 @@ int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level,
	return ret;
}

int nilfs_bmap_lookup_contig(struct nilfs_bmap *bmap, __u64 key, __u64 *ptrp,
			     unsigned maxblocks)
{
	int ret;

	down_read(&bmap->b_sem);
	ret = bmap->b_ops->bop_lookup_contig(bmap, key, ptrp, maxblocks);
	up_read(&bmap->b_sem);
	return ret;
}

/**
 * nilfs_bmap_lookup - find a record
+4 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ struct nilfs_bmap_stats {
 */
struct nilfs_bmap_operations {
	int (*bop_lookup)(const struct nilfs_bmap *, __u64, int, __u64 *);
	int (*bop_lookup_contig)(const struct nilfs_bmap *, __u64, __u64 *,
				 unsigned);
	int (*bop_insert)(struct nilfs_bmap *, __u64, __u64);
	int (*bop_delete)(struct nilfs_bmap *, __u64);
	void (*bop_clear)(struct nilfs_bmap *);
@@ -140,6 +142,7 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *);
int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *);
void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *);
int nilfs_bmap_lookup(struct nilfs_bmap *, unsigned long, unsigned long *);
int nilfs_bmap_lookup_contig(struct nilfs_bmap *, __u64, __u64 *, unsigned);
int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long);
int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long);
int nilfs_bmap_last_key(struct nilfs_bmap *, unsigned long *);
@@ -160,6 +163,7 @@ void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *);
/*
 * Internal use only
 */
struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *);
int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *,
			       union nilfs_bmap_ptr_req *);
void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *,
+84 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "btnode.h"
#include "btree.h"
#include "alloc.h"
#include "dat.h"

/**
 * struct nilfs_btree_path - A path on which B-tree operations are executed
@@ -595,6 +596,87 @@ static int nilfs_btree_lookup(const struct nilfs_bmap *bmap,
	return ret;
}

static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap,
				     __u64 key, __u64 *ptrp, unsigned maxblocks)
{
	struct nilfs_btree *btree = (struct nilfs_btree *)bmap;
	struct nilfs_btree_path *path;
	struct nilfs_btree_node *node;
	struct inode *dat = NULL;
	__u64 ptr, ptr2;
	sector_t blocknr;
	int level = NILFS_BTREE_LEVEL_NODE_MIN;
	int ret, cnt, index, maxlevel;

	path = nilfs_btree_alloc_path(btree);
	if (path == NULL)
		return -ENOMEM;
	nilfs_btree_init_path(btree, path);
	ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level);
	if (ret < 0)
		goto out;

	if (NILFS_BMAP_USE_VBN(bmap)) {
		dat = nilfs_bmap_get_dat(bmap);
		ret = nilfs_dat_translate(dat, ptr, &blocknr);
		if (ret < 0)
			goto out;
		ptr = blocknr;
	}
	cnt = 1;
	if (cnt == maxblocks)
		goto end;

	maxlevel = nilfs_btree_height(btree) - 1;
	node = nilfs_btree_get_node(btree, path, level);
	index = path[level].bp_index + 1;
	for (;;) {
		while (index < nilfs_btree_node_get_nchildren(btree, node)) {
			if (nilfs_btree_node_get_key(btree, node, index) !=
			    key + cnt)
				goto end;
			ptr2 = nilfs_btree_node_get_ptr(btree, node, index);
			if (dat) {
				ret = nilfs_dat_translate(dat, ptr2, &blocknr);
				if (ret < 0)
					goto out;
				ptr2 = blocknr;
			}
			if (ptr2 != ptr + cnt || ++cnt == maxblocks)
				goto end;
			index++;
			continue;
		}
		if (level == maxlevel)
			break;

		/* look-up right sibling node */
		node = nilfs_btree_get_node(btree, path, level + 1);
		index = path[level + 1].bp_index + 1;
		if (index >= nilfs_btree_node_get_nchildren(btree, node) ||
		    nilfs_btree_node_get_key(btree, node, index) != key + cnt)
			break;
		ptr2 = nilfs_btree_node_get_ptr(btree, node, index);
		path[level + 1].bp_index = index;

		brelse(path[level].bp_bh);
		path[level].bp_bh = NULL;
		ret = nilfs_btree_get_block(btree, ptr2, &path[level].bp_bh);
		if (ret < 0)
			goto out;
		node = nilfs_btree_get_nonroot_node(btree, path, level);
		index = 0;
		path[level].bp_index = index;
	}
 end:
	*ptrp = ptr;
	ret = cnt;
 out:
	nilfs_btree_clear_path(btree, path);
	nilfs_btree_free_path(btree, path);
	return ret;
}

static void nilfs_btree_promote_key(struct nilfs_btree *btree,
				    struct nilfs_btree_path *path,
				    int level, __u64 key)
@@ -2187,6 +2269,7 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level)

static const struct nilfs_bmap_operations nilfs_btree_ops = {
	.bop_lookup		=	nilfs_btree_lookup,
	.bop_lookup_contig	=	nilfs_btree_lookup_contig,
	.bop_insert		=	nilfs_btree_insert,
	.bop_delete		=	nilfs_btree_delete,
	.bop_clear		=	NULL,
@@ -2206,6 +2289,7 @@ static const struct nilfs_bmap_operations nilfs_btree_ops = {

static const struct nilfs_bmap_operations nilfs_btree_ops_gc = {
	.bop_lookup		=	NULL,
	.bop_lookup_contig	=	NULL,
	.bop_insert		=	NULL,
	.bop_delete		=	NULL,
	.bop_clear		=	NULL,
+43 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "page.h"
#include "direct.h"
#include "alloc.h"
#include "dat.h"

static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct)
{
@@ -62,6 +63,47 @@ static int nilfs_direct_lookup(const struct nilfs_bmap *bmap,
	return 0;
}

static int nilfs_direct_lookup_contig(const struct nilfs_bmap *bmap,
				      __u64 key, __u64 *ptrp,
				      unsigned maxblocks)
{
	struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
	struct inode *dat = NULL;
	__u64 ptr, ptr2;
	sector_t blocknr;
	int ret, cnt;

	if (key > NILFS_DIRECT_KEY_MAX ||
	    (ptr = nilfs_direct_get_ptr(direct, key)) ==
	    NILFS_BMAP_INVALID_PTR)
		return -ENOENT;

	if (NILFS_BMAP_USE_VBN(bmap)) {
		dat = nilfs_bmap_get_dat(bmap);
		ret = nilfs_dat_translate(dat, ptr, &blocknr);
		if (ret < 0)
			return ret;
		ptr = blocknr;
	}

	maxblocks = min_t(unsigned, maxblocks, NILFS_DIRECT_KEY_MAX - key + 1);
	for (cnt = 1; cnt < maxblocks &&
		     (ptr2 = nilfs_direct_get_ptr(direct, key + cnt)) !=
		     NILFS_BMAP_INVALID_PTR;
	     cnt++) {
		if (dat) {
			ret = nilfs_dat_translate(dat, ptr2, &blocknr);
			if (ret < 0)
				return ret;
			ptr2 = blocknr;
		}
		if (ptr2 != ptr + cnt)
			break;
	}
	*ptrp = ptr;
	return cnt;
}

static __u64
nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key)
{
@@ -367,6 +409,7 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap,

static const struct nilfs_bmap_operations nilfs_direct_ops = {
	.bop_lookup		=	nilfs_direct_lookup,
	.bop_lookup_contig	=	nilfs_direct_lookup_contig,
	.bop_insert		=	nilfs_direct_insert,
	.bop_delete		=	nilfs_direct_delete,
	.bop_clear		=	NULL,
+8 −7
Original line number Diff line number Diff line
@@ -43,22 +43,23 @@
 *
 * This function does not issue actual read request of the specified data
 * block. It is done by VFS.
 * Bulk read for direct-io is not supported yet. (should be supported)
 */
int nilfs_get_block(struct inode *inode, sector_t blkoff,
		    struct buffer_head *bh_result, int create)
{
	struct nilfs_inode_info *ii = NILFS_I(inode);
	unsigned long blknum = 0;
	__u64 blknum = 0;
	int err = 0, ret;
	struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode));
	unsigned maxblocks = bh_result->b_size >> inode->i_blkbits;

	/* This exclusion control is a workaround; should be revised */
	down_read(&NILFS_MDT(dat)->mi_sem);	/* XXX */
	ret = nilfs_bmap_lookup(ii->i_bmap, (unsigned long)blkoff, &blknum);
	up_read(&NILFS_MDT(dat)->mi_sem);	/* XXX */
	if (ret == 0) {	/* found */
	down_read(&NILFS_MDT(dat)->mi_sem);
	ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks);
	up_read(&NILFS_MDT(dat)->mi_sem);
	if (ret >= 0) {	/* found */
		map_bh(bh_result, inode->i_sb, blknum);
		if (ret > 0)
			bh_result->b_size = (ret << inode->i_blkbits);
		goto out;
	}
	/* data block was not found */