diff options
author | Hugh Dickins <hugh@veritas.com> | 2005-10-29 21:16:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-30 00:40:42 -0400 |
commit | 4c21e2f2441dc5fbb957b030333f5a3f2d02dea7 (patch) | |
tree | 1f76d33bb1d76221c6424bc5fed080a4f91349a6 /fs | |
parent | b38c6845b695141259019e2b7c0fe6c32a6e720d (diff) |
[PATCH] mm: split page table lock
Christoph Lameter demonstrated very poor scalability on the SGI 512-way, with
a many-threaded application which concurrently initializes different parts of
a large anonymous area.
This patch corrects that, by using a separate spinlock per page table page, to
guard the page table entries in that page, instead of using the mm's single
page_table_lock. (But even then, page_table_lock is still used to guard page
table allocation, and anon_vma allocation.)
In this implementation, the spinlock is tucked inside the struct page of the
page table page: with a BUILD_BUG_ON in case it overflows - which it would in
the case of 32-bit PA-RISC with spinlock debugging enabled.
Splitting the lock is not quite for free: another cacheline access. Ideally,
I suppose we would use split ptlock only for multi-threaded processes on
multi-cpu machines; but deciding that dynamically would have its own costs.
So for now enable it by config, at some number of cpus - since the Kconfig
language doesn't support inequalities, let preprocessor compare that with
NR_CPUS. But I don't think it's worth being user-configurable: for good
testing of both split and unsplit configs, split now at 4 cpus, and perhaps
change that to 8 later.
There is a benefit even for singly threaded processes: kswapd can be attacking
one part of the mm while another part is busy faulting.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/afs/file.c | 4 | ||||
-rw-r--r-- | fs/buffer.c | 2 | ||||
-rw-r--r-- | fs/jfs/jfs_metapage.c | 12 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.c | 7 |
4 files changed, 13 insertions, 12 deletions
diff --git a/fs/afs/file.c b/fs/afs/file.c index 0d576987ec6..4975c9c193d 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -291,8 +291,8 @@ static int afs_file_releasepage(struct page *page, gfp_t gfp_flags) | |||
291 | cachefs_uncache_page(vnode->cache, page); | 291 | cachefs_uncache_page(vnode->cache, page); |
292 | #endif | 292 | #endif |
293 | 293 | ||
294 | pageio = (struct cachefs_page *) page->private; | 294 | pageio = (struct cachefs_page *) page_private(page); |
295 | page->private = 0; | 295 | set_page_private(page, 0); |
296 | ClearPagePrivate(page); | 296 | ClearPagePrivate(page); |
297 | 297 | ||
298 | if (pageio) | 298 | if (pageio) |
diff --git a/fs/buffer.c b/fs/buffer.c index b1667986442..2066e4cb700 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -96,7 +96,7 @@ static void | |||
96 | __clear_page_buffers(struct page *page) | 96 | __clear_page_buffers(struct page *page) |
97 | { | 97 | { |
98 | ClearPagePrivate(page); | 98 | ClearPagePrivate(page); |
99 | page->private = 0; | 99 | set_page_private(page, 0); |
100 | page_cache_release(page); | 100 | page_cache_release(page); |
101 | } | 101 | } |
102 | 102 | ||
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 26091a5f88d..8a53981f9f2 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c | |||
@@ -86,7 +86,7 @@ struct meta_anchor { | |||
86 | atomic_t io_count; | 86 | atomic_t io_count; |
87 | struct metapage *mp[MPS_PER_PAGE]; | 87 | struct metapage *mp[MPS_PER_PAGE]; |
88 | }; | 88 | }; |
89 | #define mp_anchor(page) ((struct meta_anchor *)page->private) | 89 | #define mp_anchor(page) ((struct meta_anchor *)page_private(page)) |
90 | 90 | ||
91 | static inline struct metapage *page_to_mp(struct page *page, uint offset) | 91 | static inline struct metapage *page_to_mp(struct page *page, uint offset) |
92 | { | 92 | { |
@@ -108,7 +108,7 @@ static inline int insert_metapage(struct page *page, struct metapage *mp) | |||
108 | if (!a) | 108 | if (!a) |
109 | return -ENOMEM; | 109 | return -ENOMEM; |
110 | memset(a, 0, sizeof(struct meta_anchor)); | 110 | memset(a, 0, sizeof(struct meta_anchor)); |
111 | page->private = (unsigned long)a; | 111 | set_page_private(page, (unsigned long)a); |
112 | SetPagePrivate(page); | 112 | SetPagePrivate(page); |
113 | kmap(page); | 113 | kmap(page); |
114 | } | 114 | } |
@@ -136,7 +136,7 @@ static inline void remove_metapage(struct page *page, struct metapage *mp) | |||
136 | a->mp[index] = NULL; | 136 | a->mp[index] = NULL; |
137 | if (--a->mp_count == 0) { | 137 | if (--a->mp_count == 0) { |
138 | kfree(a); | 138 | kfree(a); |
139 | page->private = 0; | 139 | set_page_private(page, 0); |
140 | ClearPagePrivate(page); | 140 | ClearPagePrivate(page); |
141 | kunmap(page); | 141 | kunmap(page); |
142 | } | 142 | } |
@@ -156,13 +156,13 @@ static inline void dec_io(struct page *page, void (*handler) (struct page *)) | |||
156 | #else | 156 | #else |
157 | static inline struct metapage *page_to_mp(struct page *page, uint offset) | 157 | static inline struct metapage *page_to_mp(struct page *page, uint offset) |
158 | { | 158 | { |
159 | return PagePrivate(page) ? (struct metapage *)page->private : NULL; | 159 | return PagePrivate(page) ? (struct metapage *)page_private(page) : NULL; |
160 | } | 160 | } |
161 | 161 | ||
162 | static inline int insert_metapage(struct page *page, struct metapage *mp) | 162 | static inline int insert_metapage(struct page *page, struct metapage *mp) |
163 | { | 163 | { |
164 | if (mp) { | 164 | if (mp) { |
165 | page->private = (unsigned long)mp; | 165 | set_page_private(page, (unsigned long)mp); |
166 | SetPagePrivate(page); | 166 | SetPagePrivate(page); |
167 | kmap(page); | 167 | kmap(page); |
168 | } | 168 | } |
@@ -171,7 +171,7 @@ static inline int insert_metapage(struct page *page, struct metapage *mp) | |||
171 | 171 | ||
172 | static inline void remove_metapage(struct page *page, struct metapage *mp) | 172 | static inline void remove_metapage(struct page *page, struct metapage *mp) |
173 | { | 173 | { |
174 | page->private = 0; | 174 | set_page_private(page, 0); |
175 | ClearPagePrivate(page); | 175 | ClearPagePrivate(page); |
176 | kunmap(page); | 176 | kunmap(page); |
177 | } | 177 | } |
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index ba4767c04ad..4cd46abe843 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
@@ -181,8 +181,9 @@ set_page_region( | |||
181 | size_t offset, | 181 | size_t offset, |
182 | size_t length) | 182 | size_t length) |
183 | { | 183 | { |
184 | page->private |= page_region_mask(offset, length); | 184 | set_page_private(page, |
185 | if (page->private == ~0UL) | 185 | page_private(page) | page_region_mask(offset, length)); |
186 | if (page_private(page) == ~0UL) | ||
186 | SetPageUptodate(page); | 187 | SetPageUptodate(page); |
187 | } | 188 | } |
188 | 189 | ||
@@ -194,7 +195,7 @@ test_page_region( | |||
194 | { | 195 | { |
195 | unsigned long mask = page_region_mask(offset, length); | 196 | unsigned long mask = page_region_mask(offset, length); |
196 | 197 | ||
197 | return (mask && (page->private & mask) == mask); | 198 | return (mask && (page_private(page) & mask) == mask); |
198 | } | 199 | } |
199 | 200 | ||
200 | /* | 201 | /* |