diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2007-01-17 10:33:23 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2007-02-05 13:37:11 -0500 |
commit | fee852e374fb367c5436b1226eb93b35f8355ed9 (patch) | |
tree | 0e373afa25bd27582b2fc4fff8f2964ff0de6722 /fs | |
parent | 330005c2b23e71e54931913e9b63d1712a19e444 (diff) |
[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: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/glock.c | 66 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 2 |
2 files changed, 44 insertions, 24 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index fb1960b7fdde..5341e03b873f 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/gfs2_ondisk.h> | 19 | #include <linux/gfs2_ondisk.h> |
20 | #include <linux/list.h> | 20 | #include <linux/list.h> |
21 | #include <linux/lm_interface.h> | 21 | #include <linux/lm_interface.h> |
22 | #include <linux/wait.h> | ||
22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
23 | 24 | ||
24 | #include "gfs2.h" | 25 | #include "gfs2.h" |
@@ -395,7 +396,6 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, | |||
395 | gh->gh_flags = flags; | 396 | gh->gh_flags = flags; |
396 | gh->gh_error = 0; | 397 | gh->gh_error = 0; |
397 | gh->gh_iflags = 0; | 398 | gh->gh_iflags = 0; |
398 | init_completion(&gh->gh_wait); | ||
399 | 399 | ||
400 | if (gh->gh_state == LM_ST_EXCLUSIVE) | 400 | if (gh->gh_state == LM_ST_EXCLUSIVE) |
401 | gh->gh_flags |= GL_LOCAL_EXCL; | 401 | gh->gh_flags |= GL_LOCAL_EXCL; |
@@ -479,6 +479,29 @@ static void gfs2_holder_put(struct gfs2_holder *gh) | |||
479 | kfree(gh); | 479 | kfree(gh); |
480 | } | 480 | } |
481 | 481 | ||
482 | static void gfs2_holder_dispose_or_wake(struct gfs2_holder *gh) | ||
483 | { | ||
484 | if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) { | ||
485 | gfs2_holder_put(gh); | ||
486 | return; | ||
487 | } | ||
488 | clear_bit(HIF_WAIT, &gh->gh_iflags); | ||
489 | smp_mb(); | ||
490 | wake_up_bit(&gh->gh_iflags, HIF_WAIT); | ||
491 | } | ||
492 | |||
493 | static int holder_wait(void *word) | ||
494 | { | ||
495 | schedule(); | ||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | static void wait_on_holder(struct gfs2_holder *gh) | ||
500 | { | ||
501 | might_sleep(); | ||
502 | wait_on_bit(&gh->gh_iflags, HIF_WAIT, holder_wait, TASK_UNINTERRUPTIBLE); | ||
503 | } | ||
504 | |||
482 | /** | 505 | /** |
483 | * rq_mutex - process a mutex request in the queue | 506 | * rq_mutex - process a mutex request in the queue |
484 | * @gh: the glock holder | 507 | * @gh: the glock holder |
@@ -493,7 +516,9 @@ static int rq_mutex(struct gfs2_holder *gh) | |||
493 | list_del_init(&gh->gh_list); | 516 | list_del_init(&gh->gh_list); |
494 | /* gh->gh_error never examined. */ | 517 | /* gh->gh_error never examined. */ |
495 | set_bit(GLF_LOCK, &gl->gl_flags); | 518 | set_bit(GLF_LOCK, &gl->gl_flags); |
496 | complete(&gh->gh_wait); | 519 | clear_bit(HIF_WAIT, &gh->gh_flags); |
520 | smp_mb(); | ||
521 | wake_up_bit(&gh->gh_iflags, HIF_WAIT); | ||
497 | 522 | ||
498 | return 1; | 523 | return 1; |
499 | } | 524 | } |
@@ -549,7 +574,7 @@ static int rq_promote(struct gfs2_holder *gh) | |||
549 | gh->gh_error = 0; | 574 | gh->gh_error = 0; |
550 | set_bit(HIF_HOLDER, &gh->gh_iflags); | 575 | set_bit(HIF_HOLDER, &gh->gh_iflags); |
551 | 576 | ||
552 | complete(&gh->gh_wait); | 577 | gfs2_holder_dispose_or_wake(gh); |
553 | 578 | ||
554 | return 0; | 579 | return 0; |
555 | } | 580 | } |
@@ -573,10 +598,7 @@ static int rq_demote(struct gfs2_holder *gh) | |||
573 | list_del_init(&gh->gh_list); | 598 | list_del_init(&gh->gh_list); |
574 | gh->gh_error = 0; | 599 | gh->gh_error = 0; |
575 | spin_unlock(&gl->gl_spin); | 600 | spin_unlock(&gl->gl_spin); |
576 | if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) | 601 | gfs2_holder_dispose_or_wake(gh); |
577 | gfs2_holder_put(gh); | ||
578 | else | ||
579 | complete(&gh->gh_wait); | ||
580 | spin_lock(&gl->gl_spin); | 602 | spin_lock(&gl->gl_spin); |
581 | } else { | 603 | } else { |
582 | gl->gl_req_gh = gh; | 604 | gl->gl_req_gh = gh; |
@@ -684,6 +706,8 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl) | |||
684 | 706 | ||
685 | gfs2_holder_init(gl, 0, 0, &gh); | 707 | gfs2_holder_init(gl, 0, 0, &gh); |
686 | set_bit(HIF_MUTEX, &gh.gh_iflags); | 708 | set_bit(HIF_MUTEX, &gh.gh_iflags); |
709 | if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags)) | ||
710 | BUG(); | ||
687 | 711 | ||
688 | spin_lock(&gl->gl_spin); | 712 | spin_lock(&gl->gl_spin); |
689 | if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { | 713 | if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { |
@@ -691,11 +715,13 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl) | |||
691 | } else { | 715 | } else { |
692 | gl->gl_owner = current; | 716 | gl->gl_owner = current; |
693 | gl->gl_ip = (unsigned long)__builtin_return_address(0); | 717 | gl->gl_ip = (unsigned long)__builtin_return_address(0); |
694 | complete(&gh.gh_wait); | 718 | clear_bit(HIF_WAIT, &gh.gh_iflags); |
719 | smp_mb(); | ||
720 | wake_up_bit(&gh.gh_iflags, HIF_WAIT); | ||
695 | } | 721 | } |
696 | spin_unlock(&gl->gl_spin); | 722 | spin_unlock(&gl->gl_spin); |
697 | 723 | ||
698 | wait_for_completion(&gh.gh_wait); | 724 | wait_on_holder(&gh); |
699 | gfs2_holder_uninit(&gh); | 725 | gfs2_holder_uninit(&gh); |
700 | } | 726 | } |
701 | 727 | ||
@@ -774,6 +800,7 @@ restart: | |||
774 | return; | 800 | return; |
775 | set_bit(HIF_DEMOTE, &new_gh->gh_iflags); | 801 | set_bit(HIF_DEMOTE, &new_gh->gh_iflags); |
776 | set_bit(HIF_DEALLOC, &new_gh->gh_iflags); | 802 | set_bit(HIF_DEALLOC, &new_gh->gh_iflags); |
803 | set_bit(HIF_WAIT, &new_gh->gh_iflags); | ||
777 | 804 | ||
778 | goto restart; | 805 | goto restart; |
779 | } | 806 | } |
@@ -908,12 +935,8 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) | |||
908 | 935 | ||
909 | gfs2_glock_put(gl); | 936 | gfs2_glock_put(gl); |
910 | 937 | ||
911 | if (gh) { | 938 | if (gh) |
912 | if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) | 939 | gfs2_holder_dispose_or_wake(gh); |
913 | gfs2_holder_put(gh); | ||
914 | else | ||
915 | complete(&gh->gh_wait); | ||
916 | } | ||
917 | } | 940 | } |
918 | 941 | ||
919 | /** | 942 | /** |
@@ -999,12 +1022,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) | |||
999 | 1022 | ||
1000 | gfs2_glock_put(gl); | 1023 | gfs2_glock_put(gl); |
1001 | 1024 | ||
1002 | if (gh) { | 1025 | if (gh) |
1003 | if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) | 1026 | gfs2_holder_dispose_or_wake(gh); |
1004 | gfs2_holder_put(gh); | ||
1005 | else | ||
1006 | complete(&gh->gh_wait); | ||
1007 | } | ||
1008 | } | 1027 | } |
1009 | 1028 | ||
1010 | /** | 1029 | /** |
@@ -1105,8 +1124,7 @@ static int glock_wait_internal(struct gfs2_holder *gh) | |||
1105 | if (gh->gh_flags & LM_FLAG_PRIORITY) | 1124 | if (gh->gh_flags & LM_FLAG_PRIORITY) |
1106 | do_cancels(gh); | 1125 | do_cancels(gh); |
1107 | 1126 | ||
1108 | wait_for_completion(&gh->gh_wait); | 1127 | wait_on_holder(gh); |
1109 | |||
1110 | if (gh->gh_error) | 1128 | if (gh->gh_error) |
1111 | return gh->gh_error; | 1129 | return gh->gh_error; |
1112 | 1130 | ||
@@ -1162,6 +1180,8 @@ static void add_to_queue(struct gfs2_holder *gh) | |||
1162 | struct gfs2_holder *existing; | 1180 | struct gfs2_holder *existing; |
1163 | 1181 | ||
1164 | BUG_ON(!gh->gh_owner); | 1182 | BUG_ON(!gh->gh_owner); |
1183 | if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags)) | ||
1184 | BUG(); | ||
1165 | 1185 | ||
1166 | existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner); | 1186 | existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner); |
1167 | if (existing) { | 1187 | if (existing) { |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 9114851ac53e..a24c4af09ce0 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -128,6 +128,7 @@ enum { | |||
128 | HIF_HOLDER = 6, | 128 | HIF_HOLDER = 6, |
129 | HIF_FIRST = 7, | 129 | HIF_FIRST = 7, |
130 | HIF_ABORTED = 9, | 130 | HIF_ABORTED = 9, |
131 | HIF_WAIT = 10, | ||
131 | }; | 132 | }; |
132 | 133 | ||
133 | struct gfs2_holder { | 134 | struct gfs2_holder { |
@@ -140,7 +141,6 @@ struct gfs2_holder { | |||
140 | 141 | ||
141 | int gh_error; | 142 | int gh_error; |
142 | unsigned long gh_iflags; | 143 | unsigned long gh_iflags; |
143 | struct completion gh_wait; | ||
144 | unsigned long gh_ip; | 144 | unsigned long gh_ip; |
145 | }; | 145 | }; |
146 | 146 | ||