Commit fee852e3 authored by Steven Whitehouse's avatar Steven Whitehouse

[GFS2] Shrink gfs2_inode memory by half

Here is something I spotted (while looking for something entirely
different) the other day.

Rather than using a completion in each and every struct gfs2_holder,
this removes it in favour of hashed wait queues, thus saving a
considerable amount of memory both on the stack (where a number of
gfs2_holder structures are allocated) and in particular in the
gfs2_inode which has 8 gfs2_holder structures embedded within it.

As a result on x86_64 the gfs2_inode shrinks from 2488 bytes to
1912 bytes, a saving of 576 bytes per inode (no thats not a typo!).
In actual practice we get a much better result than that since
now that a gfs2_inode is under the 2048 byte barrier, we get two
per 4k slab page effectively halving the amount of memory required
to store gfs2_inodes.
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 330005c2
......@@ -19,6 +19,7 @@
#include <linux/gfs2_ondisk.h>
#include <linux/list.h>
#include <linux/lm_interface.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include "gfs2.h"
......@@ -395,7 +396,6 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
gh->gh_flags = flags;
gh->gh_error = 0;
gh->gh_iflags = 0;
init_completion(&gh->gh_wait);
if (gh->gh_state == LM_ST_EXCLUSIVE)
gh->gh_flags |= GL_LOCAL_EXCL;
......@@ -479,6 +479,29 @@ static void gfs2_holder_put(struct gfs2_holder *gh)
kfree(gh);
}
static void gfs2_holder_dispose_or_wake(struct gfs2_holder *gh)
{
if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) {
gfs2_holder_put(gh);
return;
}
clear_bit(HIF_WAIT, &gh->gh_iflags);
smp_mb();
wake_up_bit(&gh->gh_iflags, HIF_WAIT);
}
static int holder_wait(void *word)
{
schedule();
return 0;
}
static void wait_on_holder(struct gfs2_holder *gh)
{
might_sleep();
wait_on_bit(&gh->gh_iflags, HIF_WAIT, holder_wait, TASK_UNINTERRUPTIBLE);
}
/**
* rq_mutex - process a mutex request in the queue
* @gh: the glock holder
......@@ -493,7 +516,9 @@ static int rq_mutex(struct gfs2_holder *gh)
list_del_init(&gh->gh_list);
/* gh->gh_error never examined. */
set_bit(GLF_LOCK, &gl->gl_flags);
complete(&gh->gh_wait);
clear_bit(HIF_WAIT, &gh->gh_flags);
smp_mb();
wake_up_bit(&gh->gh_iflags, HIF_WAIT);
return 1;
}
......@@ -549,7 +574,7 @@ static int rq_promote(struct gfs2_holder *gh)
gh->gh_error = 0;
set_bit(HIF_HOLDER, &gh->gh_iflags);
complete(&gh->gh_wait);
gfs2_holder_dispose_or_wake(gh);
return 0;
}
......@@ -573,10 +598,7 @@ static int rq_demote(struct gfs2_holder *gh)
list_del_init(&gh->gh_list);
gh->gh_error = 0;
spin_unlock(&gl->gl_spin);
if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
gfs2_holder_put(gh);
else
complete(&gh->gh_wait);
gfs2_holder_dispose_or_wake(gh);
spin_lock(&gl->gl_spin);
} else {
gl->gl_req_gh = gh;
......@@ -684,6 +706,8 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
gfs2_holder_init(gl, 0, 0, &gh);
set_bit(HIF_MUTEX, &gh.gh_iflags);
if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags))
BUG();
spin_lock(&gl->gl_spin);
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
......@@ -691,11 +715,13 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
} else {
gl->gl_owner = current;
gl->gl_ip = (unsigned long)__builtin_return_address(0);
complete(&gh.gh_wait);
clear_bit(HIF_WAIT, &gh.gh_iflags);
smp_mb();
wake_up_bit(&gh.gh_iflags, HIF_WAIT);
}
spin_unlock(&gl->gl_spin);
wait_for_completion(&gh.gh_wait);
wait_on_holder(&gh);
gfs2_holder_uninit(&gh);
}
......@@ -774,6 +800,7 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state)
return;
set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
set_bit(HIF_WAIT, &new_gh->gh_iflags);
goto restart;
}
......@@ -908,12 +935,8 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_glock_put(gl);
if (gh) {
if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
gfs2_holder_put(gh);
else
complete(&gh->gh_wait);
}
if (gh)
gfs2_holder_dispose_or_wake(gh);
}
/**
......@@ -999,12 +1022,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_glock_put(gl);
if (gh) {
if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
gfs2_holder_put(gh);
else
complete(&gh->gh_wait);
}
if (gh)
gfs2_holder_dispose_or_wake(gh);
}
/**
......@@ -1105,8 +1124,7 @@ static int glock_wait_internal(struct gfs2_holder *gh)
if (gh->gh_flags & LM_FLAG_PRIORITY)
do_cancels(gh);
wait_for_completion(&gh->gh_wait);
wait_on_holder(gh);
if (gh->gh_error)
return gh->gh_error;
......@@ -1162,6 +1180,8 @@ static void add_to_queue(struct gfs2_holder *gh)
struct gfs2_holder *existing;
BUG_ON(!gh->gh_owner);
if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
BUG();
existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
if (existing) {
......
......@@ -128,6 +128,7 @@ enum {
HIF_HOLDER = 6,
HIF_FIRST = 7,
HIF_ABORTED = 9,
HIF_WAIT = 10,
};
struct gfs2_holder {
......@@ -140,7 +141,6 @@ struct gfs2_holder {
int gh_error;
unsigned long gh_iflags;
struct completion gh_wait;
unsigned long gh_ip;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment