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

Commit 009d8518 authored by Steven Whitehouse's avatar Steven Whitehouse
Browse files

GFS2: Metadata address space clean up



Since the start of GFS2, an "extra" inode has been used to store
the metadata belonging to each inode. The only reason for using
this inode was to have an extra address space, the other fields
were unused. This means that the memory usage was rather inefficient.

The reason for keeping each inode's metadata in a separate address
space is that when glocks are requested on remote nodes, we need to
be able to efficiently locate the data and metadata which relating
to that glock (inode) in order to sync or sync and invalidate it
(depending on the remotely requested lock mode).

This patch adds a new type of glock, which has in addition to
its normal fields, has an address space. This applies to all
inode and rgrp glocks (but to no other glock types which remain
as before). As a result, we no longer need to have the second
inode.

This results in three major improvements:
 1. A saving of approx 25% of memory used in caching inodes
 2. A removal of the circular dependency between inodes and glocks
 3. No confusion between "normal" and "metadata" inodes in super.c

Although the first of these is the more immediately apparent, the
second is just as important as it now enables a number of clean
ups at umount time. Those will be the subject of future patches.

Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 30ff056c
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -1061,8 +1061,8 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,


int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
{
{
	struct inode *aspace = page->mapping->host;
	struct address_space *mapping = page->mapping;
	struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
	struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping);
	struct buffer_head *bh, *head;
	struct buffer_head *bh, *head;
	struct gfs2_bufdata *bd;
	struct gfs2_bufdata *bd;


+21 −19
Original line number Original line Diff line number Diff line
@@ -154,12 +154,14 @@ static unsigned int gl_hash(const struct gfs2_sbd *sdp,
static void glock_free(struct gfs2_glock *gl)
static void glock_free(struct gfs2_glock *gl)
{
{
	struct gfs2_sbd *sdp = gl->gl_sbd;
	struct gfs2_sbd *sdp = gl->gl_sbd;
	struct inode *aspace = gl->gl_aspace;
	struct address_space *mapping = gfs2_glock2aspace(gl);
	struct kmem_cache *cachep = gfs2_glock_cachep;


	if (aspace)
	GLOCK_BUG_ON(gl, mapping && mapping->nrpages);
		gfs2_aspace_put(aspace);
	trace_gfs2_glock_put(gl);
	trace_gfs2_glock_put(gl);
	sdp->sd_lockstruct.ls_ops->lm_put_lock(gfs2_glock_cachep, gl);
	if (mapping)
		cachep = gfs2_glock_aspace_cachep;
	sdp->sd_lockstruct.ls_ops->lm_put_lock(cachep, gl);
}
}


/**
/**
@@ -750,10 +752,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
		   const struct gfs2_glock_operations *glops, int create,
		   const struct gfs2_glock_operations *glops, int create,
		   struct gfs2_glock **glp)
		   struct gfs2_glock **glp)
{
{
	struct super_block *s = sdp->sd_vfs;
	struct lm_lockname name = { .ln_number = number, .ln_type = glops->go_type };
	struct lm_lockname name = { .ln_number = number, .ln_type = glops->go_type };
	struct gfs2_glock *gl, *tmp;
	struct gfs2_glock *gl, *tmp;
	unsigned int hash = gl_hash(sdp, &name);
	unsigned int hash = gl_hash(sdp, &name);
	int error;
	struct address_space *mapping;


	read_lock(gl_lock_addr(hash));
	read_lock(gl_lock_addr(hash));
	gl = search_bucket(hash, sdp, &name);
	gl = search_bucket(hash, sdp, &name);
@@ -765,6 +768,9 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
	if (!create)
	if (!create)
		return -ENOENT;
		return -ENOENT;


	if (glops->go_flags & GLOF_ASPACE)
		gl = kmem_cache_alloc(gfs2_glock_aspace_cachep, GFP_KERNEL);
	else
		gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL);
		gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL);
	if (!gl)
	if (!gl)
		return -ENOMEM;
		return -ENOMEM;
@@ -784,18 +790,18 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
	gl->gl_tchange = jiffies;
	gl->gl_tchange = jiffies;
	gl->gl_object = NULL;
	gl->gl_object = NULL;
	gl->gl_sbd = sdp;
	gl->gl_sbd = sdp;
	gl->gl_aspace = NULL;
	INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
	INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
	INIT_WORK(&gl->gl_delete, delete_work_func);
	INIT_WORK(&gl->gl_delete, delete_work_func);


	/* If this glock protects actual on-disk data or metadata blocks,
	mapping = gfs2_glock2aspace(gl);
	   create a VFS inode to manage the pages/buffers holding them. */
	if (mapping) {
	if (glops == &gfs2_inode_glops || glops == &gfs2_rgrp_glops) {
                mapping->a_ops = &gfs2_meta_aops;
		gl->gl_aspace = gfs2_aspace_get(sdp);
		mapping->host = s->s_bdev->bd_inode;
		if (!gl->gl_aspace) {
		mapping->flags = 0;
			error = -ENOMEM;
		mapping_set_gfp_mask(mapping, GFP_NOFS);
			goto fail;
		mapping->assoc_mapping = NULL;
		}
		mapping->backing_dev_info = s->s_bdi;
		mapping->writeback_index = 0;
	}
	}


	write_lock(gl_lock_addr(hash));
	write_lock(gl_lock_addr(hash));
@@ -812,10 +818,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
	*glp = gl;
	*glp = gl;


	return 0;
	return 0;

fail:
	kmem_cache_free(gfs2_glock_cachep, gl);
	return error;
}
}


/**
/**
+7 −0
Original line number Original line Diff line number Diff line
@@ -180,6 +180,13 @@ static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl)
	return gl->gl_state == LM_ST_SHARED;
	return gl->gl_state == LM_ST_SHARED;
}
}


static inline struct address_space *gfs2_glock2aspace(struct gfs2_glock *gl)
{
	if (gl->gl_ops->go_flags & GLOF_ASPACE)
		return (struct address_space *)(gl + 1);
	return NULL;
}

int gfs2_glock_get(struct gfs2_sbd *sdp,
int gfs2_glock_get(struct gfs2_sbd *sdp,
		   u64 number, const struct gfs2_glock_operations *glops,
		   u64 number, const struct gfs2_glock_operations *glops,
		   int create, struct gfs2_glock **glp);
		   int create, struct gfs2_glock **glp);
+9 −7
Original line number Original line Diff line number Diff line
@@ -87,7 +87,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)


static void rgrp_go_sync(struct gfs2_glock *gl)
static void rgrp_go_sync(struct gfs2_glock *gl)
{
{
	struct address_space *metamapping = gl->gl_aspace->i_mapping;
	struct address_space *metamapping = gfs2_glock2aspace(gl);
	int error;
	int error;


	if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
	if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
@@ -113,7 +113,7 @@ static void rgrp_go_sync(struct gfs2_glock *gl)


static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
{
{
	struct address_space *mapping = gl->gl_aspace->i_mapping;
	struct address_space *mapping = gfs2_glock2aspace(gl);


	BUG_ON(!(flags & DIO_METADATA));
	BUG_ON(!(flags & DIO_METADATA));
	gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count));
	gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count));
@@ -134,7 +134,7 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
static void inode_go_sync(struct gfs2_glock *gl)
static void inode_go_sync(struct gfs2_glock *gl)
{
{
	struct gfs2_inode *ip = gl->gl_object;
	struct gfs2_inode *ip = gl->gl_object;
	struct address_space *metamapping = gl->gl_aspace->i_mapping;
	struct address_space *metamapping = gfs2_glock2aspace(gl);
	int error;
	int error;


	if (ip && !S_ISREG(ip->i_inode.i_mode))
	if (ip && !S_ISREG(ip->i_inode.i_mode))
@@ -183,7 +183,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
	gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count));
	gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count));


	if (flags & DIO_METADATA) {
	if (flags & DIO_METADATA) {
		struct address_space *mapping = gl->gl_aspace->i_mapping;
		struct address_space *mapping = gfs2_glock2aspace(gl);
		truncate_inode_pages(mapping, 0);
		truncate_inode_pages(mapping, 0);
		if (ip) {
		if (ip) {
			set_bit(GIF_INVALID, &ip->i_flags);
			set_bit(GIF_INVALID, &ip->i_flags);
@@ -282,7 +282,8 @@ static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)


static int rgrp_go_demote_ok(const struct gfs2_glock *gl)
static int rgrp_go_demote_ok(const struct gfs2_glock *gl)
{
{
	return !gl->gl_aspace->i_mapping->nrpages;
	const struct address_space *mapping = (const struct address_space *)(gl + 1);
	return !mapping->nrpages;
}
}


/**
/**
@@ -387,8 +388,7 @@ static void iopen_go_callback(struct gfs2_glock *gl)
	struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object;
	struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object;


	if (gl->gl_demote_state == LM_ST_UNLOCKED &&
	if (gl->gl_demote_state == LM_ST_UNLOCKED &&
	    gl->gl_state == LM_ST_SHARED &&
	    gl->gl_state == LM_ST_SHARED && ip) {
	    ip && test_bit(GIF_USER, &ip->i_flags)) {
		gfs2_glock_hold(gl);
		gfs2_glock_hold(gl);
		if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0)
		if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0)
			gfs2_glock_put_nolock(gl);
			gfs2_glock_put_nolock(gl);
@@ -407,6 +407,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
	.go_dump = inode_go_dump,
	.go_dump = inode_go_dump,
	.go_type = LM_TYPE_INODE,
	.go_type = LM_TYPE_INODE,
	.go_min_hold_time = HZ / 5,
	.go_min_hold_time = HZ / 5,
	.go_flags = GLOF_ASPACE,
};
};


const struct gfs2_glock_operations gfs2_rgrp_glops = {
const struct gfs2_glock_operations gfs2_rgrp_glops = {
@@ -418,6 +419,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
	.go_dump = gfs2_rgrp_dump,
	.go_dump = gfs2_rgrp_dump,
	.go_type = LM_TYPE_RGRP,
	.go_type = LM_TYPE_RGRP,
	.go_min_hold_time = HZ / 5,
	.go_min_hold_time = HZ / 5,
	.go_flags = GLOF_ASPACE,
};
};


const struct gfs2_glock_operations gfs2_trans_glops = {
const struct gfs2_glock_operations gfs2_trans_glops = {
+2 −2
Original line number Original line Diff line number Diff line
@@ -162,6 +162,8 @@ struct gfs2_glock_operations {
	void (*go_callback) (struct gfs2_glock *gl);
	void (*go_callback) (struct gfs2_glock *gl);
	const int go_type;
	const int go_type;
	const unsigned long go_min_hold_time;
	const unsigned long go_min_hold_time;
	const unsigned long go_flags;
#define GLOF_ASPACE 1
};
};


enum {
enum {
@@ -225,7 +227,6 @@ struct gfs2_glock {


	struct gfs2_sbd *gl_sbd;
	struct gfs2_sbd *gl_sbd;


	struct inode *gl_aspace;
	struct list_head gl_ail_list;
	struct list_head gl_ail_list;
	atomic_t gl_ail_count;
	atomic_t gl_ail_count;
	struct delayed_work gl_work;
	struct delayed_work gl_work;
@@ -258,7 +259,6 @@ enum {
	GIF_INVALID		= 0,
	GIF_INVALID		= 0,
	GIF_QD_LOCKED		= 1,
	GIF_QD_LOCKED		= 1,
	GIF_SW_PAGED		= 3,
	GIF_SW_PAGED		= 3,
	GIF_USER                = 4, /* user inode, not metadata addr space */
};
};




Loading