diff options
author | Hugh Dickins <hugh@veritas.com> | 2005-09-03 18:54:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-05 03:05:41 -0400 |
commit | fb4f88dcabdc716c7c350e09cf4a38a419b007e1 (patch) | |
tree | 1a7806e3ac8bd45eded544763324c13c9f95c0e6 /mm | |
parent | 89d09a2c80ea6baafb559b86d545fada05e14ab5 (diff) |
[PATCH] swap: get_swap_page drop swap_list_lock
Rewrite get_swap_page to allocate in just the same sequence as before, but
without holding swap_list_lock across its scan_swap_map. Decrement
nr_swap_pages and update swap_list.next in advance, while still holding
swap_list_lock. Skip full devices by testing highest_bit. Swapoff hold
swap_device_lock as well as swap_list_lock to clear SWP_WRITEOK. Reduces lock
contention when there are parallel swap devices of the same priority.
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 'mm')
-rw-r--r-- | mm/swapfile.c | 75 |
1 files changed, 36 insertions, 39 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index 62e0da8f7e6e..e54d60af6b58 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -139,7 +139,6 @@ static inline unsigned long scan_swap_map(struct swap_info_struct *si) | |||
139 | } | 139 | } |
140 | si->swap_map[offset] = 1; | 140 | si->swap_map[offset] = 1; |
141 | si->inuse_pages++; | 141 | si->inuse_pages++; |
142 | nr_swap_pages--; | ||
143 | si->cluster_next = offset+1; | 142 | si->cluster_next = offset+1; |
144 | return offset; | 143 | return offset; |
145 | } | 144 | } |
@@ -150,50 +149,45 @@ static inline unsigned long scan_swap_map(struct swap_info_struct *si) | |||
150 | 149 | ||
151 | swp_entry_t get_swap_page(void) | 150 | swp_entry_t get_swap_page(void) |
152 | { | 151 | { |
153 | struct swap_info_struct * p; | 152 | struct swap_info_struct *si; |
154 | unsigned long offset; | 153 | pgoff_t offset; |
155 | swp_entry_t entry; | 154 | int type, next; |
156 | int type, wrapped = 0; | 155 | int wrapped = 0; |
157 | 156 | ||
158 | entry.val = 0; /* Out of memory */ | ||
159 | swap_list_lock(); | 157 | swap_list_lock(); |
160 | type = swap_list.next; | ||
161 | if (type < 0) | ||
162 | goto out; | ||
163 | if (nr_swap_pages <= 0) | 158 | if (nr_swap_pages <= 0) |
164 | goto out; | 159 | goto noswap; |
165 | 160 | nr_swap_pages--; | |
166 | while (1) { | 161 | |
167 | p = &swap_info[type]; | 162 | for (type = swap_list.next; type >= 0 && wrapped < 2; type = next) { |
168 | if ((p->flags & SWP_ACTIVE) == SWP_ACTIVE) { | 163 | si = swap_info + type; |
169 | swap_device_lock(p); | 164 | next = si->next; |
170 | offset = scan_swap_map(p); | 165 | if (next < 0 || |
171 | swap_device_unlock(p); | 166 | (!wrapped && si->prio != swap_info[next].prio)) { |
172 | if (offset) { | 167 | next = swap_list.head; |
173 | entry = swp_entry(type,offset); | 168 | wrapped++; |
174 | type = swap_info[type].next; | ||
175 | if (type < 0 || | ||
176 | p->prio != swap_info[type].prio) { | ||
177 | swap_list.next = swap_list.head; | ||
178 | } else { | ||
179 | swap_list.next = type; | ||
180 | } | ||
181 | goto out; | ||
182 | } | ||
183 | } | 169 | } |
184 | type = p->next; | 170 | |
185 | if (!wrapped) { | 171 | if (!si->highest_bit) |
186 | if (type < 0 || p->prio != swap_info[type].prio) { | 172 | continue; |
187 | type = swap_list.head; | 173 | if (!(si->flags & SWP_WRITEOK)) |
188 | wrapped = 1; | 174 | continue; |
189 | } | 175 | |
190 | } else | 176 | swap_list.next = next; |
191 | if (type < 0) | 177 | swap_device_lock(si); |
192 | goto out; /* out of swap space */ | 178 | swap_list_unlock(); |
179 | offset = scan_swap_map(si); | ||
180 | swap_device_unlock(si); | ||
181 | if (offset) | ||
182 | return swp_entry(type, offset); | ||
183 | swap_list_lock(); | ||
184 | next = swap_list.next; | ||
193 | } | 185 | } |
194 | out: | 186 | |
187 | nr_swap_pages++; | ||
188 | noswap: | ||
195 | swap_list_unlock(); | 189 | swap_list_unlock(); |
196 | return entry; | 190 | return (swp_entry_t) {0}; |
197 | } | 191 | } |
198 | 192 | ||
199 | static struct swap_info_struct * swap_info_get(swp_entry_t entry) | 193 | static struct swap_info_struct * swap_info_get(swp_entry_t entry) |
@@ -1105,8 +1099,11 @@ asmlinkage long sys_swapoff(const char __user * specialfile) | |||
1105 | } | 1099 | } |
1106 | nr_swap_pages -= p->pages; | 1100 | nr_swap_pages -= p->pages; |
1107 | total_swap_pages -= p->pages; | 1101 | total_swap_pages -= p->pages; |
1102 | swap_device_lock(p); | ||
1108 | p->flags &= ~SWP_WRITEOK; | 1103 | p->flags &= ~SWP_WRITEOK; |
1104 | swap_device_unlock(p); | ||
1109 | swap_list_unlock(); | 1105 | swap_list_unlock(); |
1106 | |||
1110 | current->flags |= PF_SWAPOFF; | 1107 | current->flags |= PF_SWAPOFF; |
1111 | err = try_to_unuse(type); | 1108 | err = try_to_unuse(type); |
1112 | current->flags &= ~PF_SWAPOFF; | 1109 | current->flags &= ~PF_SWAPOFF; |