aboutsummaryrefslogtreecommitdiffstats
path: root/mm/swapfile.c
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2005-09-03 18:54:37 -0400
committerLinus Torvalds <torvalds@evo.osdl.org>2005-09-05 03:05:41 -0400
commitfb4f88dcabdc716c7c350e09cf4a38a419b007e1 (patch)
tree1a7806e3ac8bd45eded544763324c13c9f95c0e6 /mm/swapfile.c
parent89d09a2c80ea6baafb559b86d545fada05e14ab5 (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/swapfile.c')
-rw-r--r--mm/swapfile.c75
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
151swp_entry_t get_swap_page(void) 150swp_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 }
194out: 186
187 nr_swap_pages++;
188noswap:
195 swap_list_unlock(); 189 swap_list_unlock();
196 return entry; 190 return (swp_entry_t) {0};
197} 191}
198 192
199static struct swap_info_struct * swap_info_get(swp_entry_t entry) 193static 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;