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

Commit fd88de56 authored by Steven Whitehouse's avatar Steven Whitehouse
Browse files

[GFS2] Readpages support

This adds readpages support (and also corrects a small bug in
the readpage error path at the same time). Hopefully this will
improve performance by allowing GFS to submit larger lumps of
I/O at a time.

In order to simplify the setting of BH_Boundary, it currently gets
set when we hit the end of a indirect pointer block. There is
always a boundary at this point with the current allocation code.
It doesn't get all the boundaries right though, so there is still
room for improvement in this.

See comments in fs/gfs2/ops_address.c for further information about
readpages with GFS2.

Signed-off-by: Steven Whitehouse
parent 5bb76af1
Loading
Loading
Loading
Loading
+108 −62
Original line number Diff line number Diff line
@@ -314,13 +314,17 @@ static void find_metapath(struct gfs2_inode *ip, uint64_t block,
 * metadata tree.
 */

static inline uint64_t *metapointer(struct buffer_head *bh,
				    unsigned int height, struct metapath *mp)
static inline u64 *metapointer(struct buffer_head *bh, int *boundary,
			       unsigned int height, const struct metapath *mp)
{
	unsigned int head_size = (height > 0) ?
		sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);

	return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
	u64 *ptr;
	*boundary = 0;
	ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height];
	if (ptr + 1 == (u64*)(bh->b_data + bh->b_size))
		*boundary = 1;
	return ptr;
}

/**
@@ -339,24 +343,24 @@ static inline uint64_t *metapointer(struct buffer_head *bh,
 *
 */

static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
			unsigned int height, struct metapath *mp, int create,
			int *new, uint64_t *block)
{
	uint64_t *ptr = metapointer(bh, height, mp);
	int boundary;
	uint64_t *ptr = metapointer(bh, &boundary, height, mp);

	if (*ptr) {
		*block = be64_to_cpu(*ptr);
		return;
		return boundary;
	}

	*block = 0;

	if (!create)
		return;
		return 0;

	if (height == ip->i_di.di_height - 1 &&
	    !gfs2_is_dir(ip))
	if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip))
		*block = gfs2_alloc_data(ip);
	else
		*block = gfs2_alloc_meta(ip);
@@ -367,15 +371,16 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
	ip->i_di.di_blocks++;

	*new = 1;
	return 0;
}

/**
 * gfs2_block_map - Map a block from an inode to a disk block
 * @ip: The GFS2 inode
 * gfs2_block_pointers - Map a block from an inode to a disk block
 * @inode: The inode
 * @lblock: The logical block number
 * @new: Value/Result argument (1 = may create/did create new blocks)
 * @dblock: the disk block number of the start of an extent
 * @extlen: the size of the extent
 * @boundary: gets set if we've hit a block boundary
 * @mp: metapath to use
 *
 * Find the block number on the current device which corresponds to an
 * inode's block. If the block had to be created, "new" will be set.
@@ -383,12 +388,14 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
 * Returns: errno
 */

int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
		   uint64_t *dblock, uint32_t *extlen)
static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock,
					       int *new, u64 *dblock,
					       int *boundary,
					       struct metapath *mp)
{
	struct gfs2_inode *ip = inode->u.generic_ip;
	struct gfs2_sbd *sdp = ip->i_sbd;
	struct buffer_head *bh;
	struct metapath mp;
	int create = *new;
	unsigned int bsize;
	unsigned int height;
@@ -398,13 +405,6 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,

	*new = 0;
	*dblock = 0;
	if (extlen)
		*extlen = 0;

	if (create)
		down_write(&ip->i_rw_mutex);
	else
		down_read(&ip->i_rw_mutex);

	if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
		goto out;
@@ -421,7 +421,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
			goto out;
	}

	find_metapath(ip, lblock, &mp);
	find_metapath(ip, lblock, mp);
	end_of_metadata = ip->i_di.di_height - 1;

	error = gfs2_meta_inode_buffer(ip, &bh);
@@ -429,7 +429,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
		goto out;

	for (x = 0; x < end_of_metadata; x++) {
		lookup_block(ip, bh, x, &mp, create, new, dblock);
		lookup_block(ip, bh, x, mp, create, new, dblock);
		brelse(bh);
		if (!*dblock)
			goto out;
@@ -439,49 +439,95 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
			goto out;
	}

	lookup_block(ip, bh, end_of_metadata, &mp, create, new, dblock);
	*boundary = lookup_block(ip, bh, end_of_metadata, mp, create, new, dblock);
	if (*new) {
		struct buffer_head *dibh;
		error = gfs2_meta_inode_buffer(ip, &dibh);
		if (!error) {
			gfs2_trans_add_bh(ip->i_gl, dibh, 1);
			gfs2_dinode_out(&ip->i_di, dibh->b_data);
			brelse(dibh);
		}
	}
	return bh;
out:
	return ERR_PTR(error);
}


static inline void bmap_lock(struct inode *inode, int create)
{
	struct gfs2_inode *ip = inode->u.generic_ip;
	if (create)
		down_write(&ip->i_rw_mutex);
	else
		down_read(&ip->i_rw_mutex);
}

static inline void bmap_unlock(struct inode *inode, int create)
{
	struct gfs2_inode *ip = inode->u.generic_ip;
	if (create)
		up_write(&ip->i_rw_mutex);
	else
		up_read(&ip->i_rw_mutex);
}

	if (extlen && *dblock) {
int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary)
{
	struct metapath mp;
	struct buffer_head *bh;
	int create = *new;

	bmap_lock(inode, create);
	bh = gfs2_block_pointers(inode, lblock, new, dblock, boundary, &mp);
	bmap_unlock(inode, create);
	if (!bh)
		return 0;
	if (IS_ERR(bh))
		return PTR_ERR(bh);
	brelse(bh);
	return 0;
}

int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen)
{
	struct gfs2_inode *ip = inode->u.generic_ip;
	struct gfs2_sbd *sdp = ip->i_sbd;
	struct metapath mp;
	struct buffer_head *bh;
	int boundary;
	int create = *new;

	BUG_ON(!extlen);
	BUG_ON(!dblock);
	BUG_ON(!new);

	bmap_lock(inode, create);
	bh = gfs2_block_pointers(inode, lblock, new, dblock, &boundary, &mp);
	*extlen = 1;

		if (!*new) {
			uint64_t tmp_dblock;
	if (bh && !IS_ERR(bh) && *dblock && !*new) {
		u64 tmp_dblock;
		int tmp_new;
		unsigned int nptrs;
		unsigned end_of_metadata = ip->i_di.di_height - 1;
		
			nptrs = (end_of_metadata) ? sdp->sd_inptrs :
						    sdp->sd_diptrs;

		nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs;
		while (++mp.mp_list[end_of_metadata] < nptrs) {
				lookup_block(ip, bh, end_of_metadata, &mp,
					     0, &tmp_new, &tmp_dblock);

			lookup_block(ip, bh, end_of_metadata, &mp, 0, &tmp_new, &tmp_dblock);
			if (*dblock + *extlen != tmp_dblock)
				break;

			(*extlen)++;
		}
	}
	}

	brelse(bh);

	if (*new) {
		error = gfs2_meta_inode_buffer(ip, &bh);
		if (!error) {
			gfs2_trans_add_bh(ip->i_gl, bh, 1);
			gfs2_dinode_out(&ip->i_di, bh->b_data);
	bmap_unlock(inode, create);
	if (!bh)
		return 0;
	if (IS_ERR(bh))
		return PTR_ERR(bh);
	brelse(bh);
		}
	}

 out:
	if (create)
		up_write(&ip->i_rw_mutex);
	else
		up_read(&ip->i_rw_mutex);

	return error;
	return 0;
}

/**
@@ -1053,7 +1099,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset,
	}

	for (; lblock < lblock_stop; lblock += extlen) {
		error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen);
		error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen);
		if (error)
			return error;

+2 −3
Original line number Diff line number Diff line
@@ -16,9 +16,8 @@ typedef int (*gfs2_unstuffer_t) (struct gfs2_inode * ip,
int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer,
			void *private);

int gfs2_block_map(struct gfs2_inode *ip,
		   uint64_t lblock, int *new,
		   uint64_t *dblock, uint32_t *extlen);
int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary);
int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);

int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size);
int gfs2_truncatei_resume(struct gfs2_inode *ip);
+4 −4
Original line number Diff line number Diff line
@@ -197,8 +197,8 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,

		if (!extlen) {
			new = 1;
			error = gfs2_block_map(ip, lblock, &new, &dblock,
					       &extlen);
			error = gfs2_extent_map(ip->i_vnode, lblock, &new,
						&dblock, &extlen);
			if (error)
				goto fail;
			error = -EIO;
@@ -314,8 +314,8 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf,

		if (!extlen) {
			new = 0;
			error = gfs2_block_map(ip, lblock, &new, &dblock,
					       &extlen);
			error = gfs2_extent_map(ip->i_vnode, lblock, &new,
						&dblock, &extlen);
			if (error)
				goto fail;
		}
+1 −1
Original line number Diff line number Diff line
@@ -2125,7 +2125,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
		mutex_lock(&sdp->sd_invalidate_inodes_mutex);
		invalidate_inodes(sdp->sd_vfs);
		mutex_unlock(&sdp->sd_invalidate_inodes_mutex);
		yield();
		msleep(10);
	}
}

+2 −3
Original line number Diff line number Diff line
@@ -1606,8 +1606,7 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh)
	curtime = get_seconds();
	if (curtime - ip->i_di.di_atime >= quantum) {
		gfs2_glock_dq(gh);
		gfs2_holder_reinit(LM_ST_EXCLUSIVE,
				  gh->gh_flags & ~LM_FLAG_ANY,
		gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY,
				   gh);
		error = gfs2_glock_nq(gh);
		if (error)
Loading