aboutsummaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2008-02-05 01:28:54 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:15 -0500
commitb409f9fcf04692c0f603d28c73d2e3dfed27bf54 (patch)
treede287c277045c72c485867a52b37f4e7d0c5815a /mm/shmem.c
parent2e0e26c76a35de8f8bec6b2b917518cfeb52888a (diff)
tmpfs: radix_tree_preloading
Nick has observed that shmem.c still uses GFP_ATOMIC when adding to page cache or swap cache, without any radix tree preload: so tending to deplete emergency reserves of memory. GFP_ATOMIC remains appropriate in shmem_writepage's add_to_swap_cache: it's being called under memory pressure, so must not wait for more memory to become available. But shmem_unuse_inode now has a window in which it can and should preload with GFP_KERNEL, and say GFP_NOWAIT instead of GFP_ATOMIC in its add_to_page_cache. shmem_getpage is not so straightforward: its filepage/swappage integrity relies upon exchanging between caches under spinlock, and it would need a lot of restructuring to place the preloads correctly. Instead, follow its pattern of retrying on races: use GFP_NOWAIT instead of GFP_ATOMIC in add_to_page_cache, and begin each circuit of the repeat loop with a sleeping radix_tree_preload, followed immediately by radix_tree_preload_end - that won't guarantee success in the next add_to_page_cache, but doesn't need to. And we can then remove that bothersome congestion_wait: when needed, it'll automatically get done in the course of the radix_tree_preload. Signed-off-by: Hugh Dickins <hugh@veritas.com> Looks-good-to: Nick Piggin <npiggin@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index a0126c437105..530c5033d028 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -901,12 +901,16 @@ found:
901 error = 1; 901 error = 1;
902 if (!inode) 902 if (!inode)
903 goto out; 903 goto out;
904 error = radix_tree_preload(GFP_KERNEL);
905 if (error)
906 goto out;
907 error = 1;
904 908
905 spin_lock(&info->lock); 909 spin_lock(&info->lock);
906 ptr = shmem_swp_entry(info, idx, NULL); 910 ptr = shmem_swp_entry(info, idx, NULL);
907 if (ptr && ptr->val == entry.val) 911 if (ptr && ptr->val == entry.val)
908 error = add_to_page_cache(page, inode->i_mapping, 912 error = add_to_page_cache(page, inode->i_mapping,
909 idx, GFP_ATOMIC); 913 idx, GFP_NOWAIT);
910 if (error == -EEXIST) { 914 if (error == -EEXIST) {
911 struct page *filepage = find_get_page(inode->i_mapping, idx); 915 struct page *filepage = find_get_page(inode->i_mapping, idx);
912 error = 1; 916 error = 1;
@@ -931,6 +935,7 @@ found:
931 if (ptr) 935 if (ptr)
932 shmem_swp_unmap(ptr); 936 shmem_swp_unmap(ptr);
933 spin_unlock(&info->lock); 937 spin_unlock(&info->lock);
938 radix_tree_preload_end();
934out: 939out:
935 unlock_page(page); 940 unlock_page(page);
936 page_cache_release(page); 941 page_cache_release(page);
@@ -1185,6 +1190,16 @@ repeat:
1185 goto done; 1190 goto done;
1186 error = 0; 1191 error = 0;
1187 gfp = mapping_gfp_mask(mapping); 1192 gfp = mapping_gfp_mask(mapping);
1193 if (!filepage) {
1194 /*
1195 * Try to preload while we can wait, to not make a habit of
1196 * draining atomic reserves; but don't latch on to this cpu.
1197 */
1198 error = radix_tree_preload(gfp & ~__GFP_HIGHMEM);
1199 if (error)
1200 goto failed;
1201 radix_tree_preload_end();
1202 }
1188 1203
1189 spin_lock(&info->lock); 1204 spin_lock(&info->lock);
1190 shmem_recalc_inode(inode); 1205 shmem_recalc_inode(inode);
@@ -1266,7 +1281,7 @@ repeat:
1266 set_page_dirty(filepage); 1281 set_page_dirty(filepage);
1267 swap_free(swap); 1282 swap_free(swap);
1268 } else if (!(error = add_to_page_cache( 1283 } else if (!(error = add_to_page_cache(
1269 swappage, mapping, idx, GFP_ATOMIC))) { 1284 swappage, mapping, idx, GFP_NOWAIT))) {
1270 info->flags |= SHMEM_PAGEIN; 1285 info->flags |= SHMEM_PAGEIN;
1271 shmem_swp_set(info, entry, 0); 1286 shmem_swp_set(info, entry, 0);
1272 shmem_swp_unmap(entry); 1287 shmem_swp_unmap(entry);
@@ -1280,10 +1295,6 @@ repeat:
1280 spin_unlock(&info->lock); 1295 spin_unlock(&info->lock);
1281 unlock_page(swappage); 1296 unlock_page(swappage);
1282 page_cache_release(swappage); 1297 page_cache_release(swappage);
1283 if (error == -ENOMEM) {
1284 /* let kswapd refresh zone for GFP_ATOMICs */
1285 congestion_wait(WRITE, HZ/50);
1286 }
1287 goto repeat; 1298 goto repeat;
1288 } 1299 }
1289 } else if (sgp == SGP_READ && !filepage) { 1300 } else if (sgp == SGP_READ && !filepage) {
@@ -1338,7 +1349,7 @@ repeat:
1338 shmem_swp_unmap(entry); 1349 shmem_swp_unmap(entry);
1339 } 1350 }
1340 if (error || swap.val || 0 != add_to_page_cache_lru( 1351 if (error || swap.val || 0 != add_to_page_cache_lru(
1341 filepage, mapping, idx, GFP_ATOMIC)) { 1352 filepage, mapping, idx, GFP_NOWAIT)) {
1342 spin_unlock(&info->lock); 1353 spin_unlock(&info->lock);
1343 page_cache_release(filepage); 1354 page_cache_release(filepage);
1344 shmem_unacct_blocks(info->flags, 1); 1355 shmem_unacct_blocks(info->flags, 1);