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: Steven Whitehouse <swhiteho@redhat.com>
#include <linux/gfs2_ondisk.h>
#include <linux/list.h>
#include <linux/lm_interface.h>
#include <linux/gfs2_ondisk.h>
#include <linux/list.h>
#include <linux/lm_interface.h>
#include <asm/uaccess.h>
#include "gfs2.h"
#include <asm/uaccess.h>
#include "gfs2.h"
gh->gh_flags = flags;
gh->gh_error = 0;
gh->gh_iflags = 0;
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;
if (gh->gh_state == LM_ST_EXCLUSIVE)
gh->gh_flags |= GL_LOCAL_EXCL;
+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
/**
* rq_mutex - process a mutex request in the queue
* @gh: the glock holder
list_del_init(&gh->gh_list);
/* gh->gh_error never examined. */
set_bit(GLF_LOCK, &gl->gl_flags);
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);
gh->gh_error = 0;
set_bit(HIF_HOLDER, &gh->gh_iflags);
gh->gh_error = 0;
set_bit(HIF_HOLDER, &gh->gh_iflags);
- complete(&gh->gh_wait);
+ gfs2_holder_dispose_or_wake(gh);
list_del_init(&gh->gh_list);
gh->gh_error = 0;
spin_unlock(&gl->gl_spin);
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;
spin_lock(&gl->gl_spin);
} else {
gl->gl_req_gh = gh;
gfs2_holder_init(gl, 0, 0, &gh);
set_bit(HIF_MUTEX, &gh.gh_iflags);
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)) {
spin_lock(&gl->gl_spin);
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
} else {
gl->gl_owner = current;
gl->gl_ip = (unsigned long)__builtin_return_address(0);
} else {
gl->gl_owner = current;
gl->gl_ip = (unsigned long)__builtin_return_address(0);
+ 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);
gfs2_holder_uninit(&gh);
}
gfs2_holder_uninit(&gh);
}
return;
set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
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);
- 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);
- 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);
if (gh->gh_flags & LM_FLAG_PRIORITY)
do_cancels(gh);
if (gh->gh_flags & LM_FLAG_PRIORITY)
do_cancels(gh);
- wait_for_completion(&gh->gh_wait);
-
if (gh->gh_error)
return gh->gh_error;
if (gh->gh_error)
return gh->gh_error;
struct gfs2_holder *existing;
BUG_ON(!gh->gh_owner);
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) {
existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
if (existing) {
HIF_HOLDER = 6,
HIF_FIRST = 7,
HIF_ABORTED = 9,
HIF_HOLDER = 6,
HIF_FIRST = 7,
HIF_ABORTED = 9,
int gh_error;
unsigned long gh_iflags;
int gh_error;
unsigned long gh_iflags;
- struct completion gh_wait;