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 @@ ...@@ -19,6 +19,7 @@
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/lm_interface.h> #include <linux/lm_interface.h>
#include <linux/wait.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "gfs2.h" #include "gfs2.h"
...@@ -395,7 +396,6 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, ...@@ -395,7 +396,6 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
gh->gh_flags = flags; gh->gh_flags = flags;
gh->gh_error = 0; gh->gh_error = 0;
gh->gh_iflags = 0; gh->gh_iflags = 0;
init_completion(&gh->gh_wait);
if (gh->gh_state == LM_ST_EXCLUSIVE) if (gh->gh_state == LM_ST_EXCLUSIVE)
gh->gh_flags |= GL_LOCAL_EXCL; gh->gh_flags |= GL_LOCAL_EXCL;
...@@ -479,6 +479,29 @@ static void gfs2_holder_put(struct gfs2_holder *gh) ...@@ -479,6 +479,29 @@ static void gfs2_holder_put(struct gfs2_holder *gh)
kfree(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 * rq_mutex - process a mutex request in the queue
* @gh: the glock holder * @gh: the glock holder
...@@ -493,7 +516,9 @@ static int rq_mutex(struct gfs2_holder *gh) ...@@ -493,7 +516,9 @@ static int rq_mutex(struct gfs2_holder *gh)
list_del_init(&gh->gh_list); list_del_init(&gh->gh_list);
/* gh->gh_error never examined. */ /* gh->gh_error never examined. */
set_bit(GLF_LOCK, &gl->gl_flags); 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; return 1;
} }
...@@ -549,7 +574,7 @@ static int rq_promote(struct gfs2_holder *gh) ...@@ -549,7 +574,7 @@ static int rq_promote(struct gfs2_holder *gh)
gh->gh_error = 0; gh->gh_error = 0;
set_bit(HIF_HOLDER, &gh->gh_iflags); set_bit(HIF_HOLDER, &gh->gh_iflags);
complete(&gh->gh_wait); gfs2_holder_dispose_or_wake(gh);
return 0; return 0;
} }
...@@ -573,10 +598,7 @@ static int rq_demote(struct gfs2_holder *gh) ...@@ -573,10 +598,7 @@ static int rq_demote(struct gfs2_holder *gh)
list_del_init(&gh->gh_list); list_del_init(&gh->gh_list);
gh->gh_error = 0; gh->gh_error = 0;
spin_unlock(&gl->gl_spin); spin_unlock(&gl->gl_spin);
if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) gfs2_holder_dispose_or_wake(gh);
gfs2_holder_put(gh);
else
complete(&gh->gh_wait);
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
} else { } else {
gl->gl_req_gh = gh; gl->gl_req_gh = gh;
...@@ -684,6 +706,8 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl) ...@@ -684,6 +706,8 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
gfs2_holder_init(gl, 0, 0, &gh); gfs2_holder_init(gl, 0, 0, &gh);
set_bit(HIF_MUTEX, &gh.gh_iflags); set_bit(HIF_MUTEX, &gh.gh_iflags);
if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags))
BUG();
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
...@@ -691,11 +715,13 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl) ...@@ -691,11 +715,13 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
} else { } else {
gl->gl_owner = current; gl->gl_owner = current;
gl->gl_ip = (unsigned long)__builtin_return_address(0); 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); spin_unlock(&gl->gl_spin);
wait_for_completion(&gh.gh_wait); wait_on_holder(&gh);
gfs2_holder_uninit(&gh); gfs2_holder_uninit(&gh);
} }
...@@ -774,6 +800,7 @@ restart: ...@@ -774,6 +800,7 @@ restart:
return; return;
set_bit(HIF_DEMOTE, &new_gh->gh_iflags); set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
set_bit(HIF_DEALLOC, &new_gh->gh_iflags); set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
set_bit(HIF_WAIT, &new_gh->gh_iflags);
goto restart; goto restart;
} }
...@@ -908,12 +935,8 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) ...@@ -908,12 +935,8 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_glock_put(gl); gfs2_glock_put(gl);
if (gh) { if (gh)
if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) gfs2_holder_dispose_or_wake(gh);
gfs2_holder_put(gh);
else
complete(&gh->gh_wait);
}
} }
/** /**
...@@ -999,12 +1022,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) ...@@ -999,12 +1022,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_glock_put(gl); gfs2_glock_put(gl);
if (gh) { if (gh)
if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) gfs2_holder_dispose_or_wake(gh);
gfs2_holder_put(gh);
else
complete(&gh->gh_wait);
}
} }
/** /**
...@@ -1105,8 +1124,7 @@ static int glock_wait_internal(struct gfs2_holder *gh) ...@@ -1105,8 +1124,7 @@ static int glock_wait_internal(struct gfs2_holder *gh)
if (gh->gh_flags & LM_FLAG_PRIORITY) if (gh->gh_flags & LM_FLAG_PRIORITY)
do_cancels(gh); do_cancels(gh);
wait_for_completion(&gh->gh_wait); wait_on_holder(gh);
if (gh->gh_error) if (gh->gh_error)
return gh->gh_error; return gh->gh_error;
...@@ -1162,6 +1180,8 @@ static void add_to_queue(struct gfs2_holder *gh) ...@@ -1162,6 +1180,8 @@ static void add_to_queue(struct gfs2_holder *gh)
struct gfs2_holder *existing; struct gfs2_holder *existing;
BUG_ON(!gh->gh_owner); 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); existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
if (existing) { if (existing) {
......
...@@ -128,6 +128,7 @@ enum { ...@@ -128,6 +128,7 @@ enum {
HIF_HOLDER = 6, HIF_HOLDER = 6,
HIF_FIRST = 7, HIF_FIRST = 7,
HIF_ABORTED = 9, HIF_ABORTED = 9,
HIF_WAIT = 10,
}; };
struct gfs2_holder { struct gfs2_holder {
...@@ -140,7 +141,6 @@ struct gfs2_holder { ...@@ -140,7 +141,6 @@ struct gfs2_holder {
int gh_error; int gh_error;
unsigned long gh_iflags; unsigned long gh_iflags;
struct completion gh_wait;
unsigned long gh_ip; 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