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

[GFS2] Use a bio to read the superblock



This means that we don't need to create a special inode just to contain
a struct address_space in order to read a single disk block. Instead
we read the disk block directly. Its slightly faster, and uses slightly
less memory, but the real reason for doing this is that it removes a
special case from the glock code.

Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent ae4a3820
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -311,8 +311,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, uint64_t number,
	/* If this glock protects actual on-disk data or metadata blocks,
	   create a VFS inode to manage the pages/buffers holding them. */
	if (glops == &gfs2_inode_glops ||
	    glops == &gfs2_rgrp_glops ||
	    glops == &gfs2_meta_glops) {
	    glops == &gfs2_rgrp_glops) {
		gl->gl_aspace = gfs2_aspace_get(sdp);
		if (!gl->gl_aspace) {
			error = -ENOMEM;
+4 −18
Original line number Diff line number Diff line
@@ -156,18 +156,6 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags)
	gl->gl_vn++;
}

/**
 * meta_go_demote_ok - Check to see if it's ok to unlock a glock
 * @gl: the glock
 *
 * Returns: 1 if we have no cached data; ok to demote meta glock
 */

static int meta_go_demote_ok(struct gfs2_glock *gl)
{
	return !gl->gl_aspace->i_mapping->nrpages;
}

/**
 * inode_go_xmote_th - promote/demote a glock
 * @gl: the glock
@@ -338,12 +326,13 @@ static void inode_go_unlock(struct gfs2_holder *gh)
	struct gfs2_glock *gl = gh->gh_gl;
	struct gfs2_inode *ip = gl->gl_object;

	if (ip && test_bit(GLF_DIRTY, &gl->gl_flags))
	if (ip) {
		if (test_bit(GLF_DIRTY, &gl->gl_flags))
			gfs2_inode_attr_in(ip);

	if (ip)
		gfs2_meta_cache_flush(ip);
	}
}

/**
 * inode_greedy -
@@ -507,9 +496,6 @@ static int quota_go_demote_ok(struct gfs2_glock *gl)
struct gfs2_glock_operations gfs2_meta_glops = {
	.go_xmote_th = gfs2_glock_xmote_th,
	.go_drop_th = gfs2_glock_drop_th,
	.go_sync = meta_go_sync,
	.go_inval = meta_go_inval,
	.go_demote_ok = meta_go_demote_ok,
	.go_type = LM_TYPE_META
};

+0 −5
Original line number Diff line number Diff line
@@ -310,11 +310,6 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
		       sdp->sd_sb.sb_bsize, (unsigned int)PAGE_SIZE);
		goto out;
	}

	/* Get rid of buffers from the original block size */
	sb_gh.gh_gl->gl_ops->go_inval(sb_gh.gh_gl, DIO_METADATA | DIO_DATA);
	sb_gh.gh_gl->gl_aspace->i_blkbits = sdp->sd_sb.sb_bsize_shift;

	sb_set_blocksize(sb, sdp->sd_sb.sb_bsize);

	/* Get the root inode */
+59 −10
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/buffer_head.h>
#include <linux/crc32.h>
#include <linux/gfs2_ondisk.h>
#include <linux/bio.h>

#include "gfs2.h"
#include "lm_interface.h"
@@ -157,6 +158,54 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent)
	return 0;
}


static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error)
{
	struct page *page = bio->bi_private;
	if (bio->bi_size)
		return 1;

	if (!error)
		SetPageUptodate(page);
	unlock_page(page);
	return 0;
}

static struct page *gfs2_read_super(struct super_block *sb, sector_t sector)
{
	struct page *page;
	struct bio *bio;

	page = alloc_page(GFP_KERNEL);
	if (unlikely(!page))
		return NULL;

	ClearPageUptodate(page);
	ClearPageDirty(page);
	lock_page(page);

	bio = bio_alloc(GFP_KERNEL, 1);
	if (unlikely(!bio)) {
		__free_page(page);
		return NULL;
	}

	bio->bi_sector = sector;
	bio->bi_bdev = sb->s_bdev;
	bio_add_page(bio, page, PAGE_SIZE, 0);

	bio->bi_end_io = end_bio_io_page;
	bio->bi_private = page;
	submit_bio(READ | BIO_RW_SYNC, bio);
	wait_on_page_locked(page);
	bio_put(bio);
	if (!PageUptodate(page)) {
		__free_page(page);
		return NULL;
	}
	return page;
}

/**
 * gfs2_read_sb - Read super block
 * @sdp: The GFS2 superblock
@@ -167,23 +216,23 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent)

int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent)
{
	struct buffer_head *bh;
	uint32_t hash_blocks, ind_blocks, leaf_blocks;
	uint32_t tmp_blocks;
	unsigned int x;
	int error;
	struct page *page;
	char *sb;

	error = gfs2_meta_read(gl, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift,
			       DIO_FORCE | DIO_START | DIO_WAIT, &bh);
	if (error) {
	page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
	if (!page) {
		if (!silent)
			fs_err(sdp, "can't read superblock\n");
		return error;
		return -EIO;
	}

	gfs2_assert(sdp, sizeof(struct gfs2_sb) <= bh->b_size);
	gfs2_sb_in(&sdp->sd_sb, bh->b_data);
	brelse(bh);
	sb = kmap(page);
	gfs2_sb_in(&sdp->sd_sb, sb);
	kunmap(page);
	__free_page(page);

	error = gfs2_check_sb(sdp, &sdp->sd_sb, silent);
	if (error)