diff options
author | David Rientjes <rientjes@google.com> | 2007-10-17 02:26:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:42:46 -0400 |
commit | d773ed6b856a96bd6d18b6e04455e3ced0876da4 (patch) | |
tree | f0235be6843ec323aeedcdadbee34a777b6c2690 | |
parent | ae74138da609c576b221c765efa8b81b2365f465 (diff) |
mm: test and set zone reclaim lock before starting reclaim
Introduces new zone flag interface for testing and setting flags:
int zone_test_and_set_flag(struct zone *zone, zone_flags_t flag)
Instead of setting and clearing ZONE_RECLAIM_LOCKED each time shrink_zone() is
called, this flag is test and set before starting zone reclaim. Zone reclaim
starts in __alloc_pages() when a zone's watermark fails and the system is in
zone_reclaim_mode. If it's already in reclaim, there's no need to start again
so it is simply considered full for that allocation attempt.
There is a change of behavior with regard to concurrent zone shrinking. It is
now possible for try_to_free_pages() or kswapd to already be shrinking a
particular zone when __alloc_pages() starts zone reclaim. In this case, it is
possible for two concurrent threads to invoke shrink_zone() for a single zone.
This change forbids a zone to be in zone reclaim twice, which was always the
behavior, but allows for concurrent try_to_free_pages() or kswapd shrinking
when starting zone reclaim.
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Christoph Lameter <clameter@sgi.com>
Signed-off-by: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/mmzone.h | 8 | ||||
-rw-r--r-- | mm/vmscan.c | 23 |
2 files changed, 21 insertions, 10 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 9011505e740d..4c4522a51a3b 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h | |||
@@ -351,6 +351,12 @@ static inline void zone_set_flag(struct zone *zone, zone_flags_t flag) | |||
351 | { | 351 | { |
352 | set_bit(flag, &zone->flags); | 352 | set_bit(flag, &zone->flags); |
353 | } | 353 | } |
354 | |||
355 | static inline int zone_test_and_set_flag(struct zone *zone, zone_flags_t flag) | ||
356 | { | ||
357 | return test_and_set_bit(flag, &zone->flags); | ||
358 | } | ||
359 | |||
354 | static inline void zone_clear_flag(struct zone *zone, zone_flags_t flag) | 360 | static inline void zone_clear_flag(struct zone *zone, zone_flags_t flag) |
355 | { | 361 | { |
356 | clear_bit(flag, &zone->flags); | 362 | clear_bit(flag, &zone->flags); |
@@ -360,10 +366,12 @@ static inline int zone_is_all_unreclaimable(const struct zone *zone) | |||
360 | { | 366 | { |
361 | return test_bit(ZONE_ALL_UNRECLAIMABLE, &zone->flags); | 367 | return test_bit(ZONE_ALL_UNRECLAIMABLE, &zone->flags); |
362 | } | 368 | } |
369 | |||
363 | static inline int zone_is_reclaim_locked(const struct zone *zone) | 370 | static inline int zone_is_reclaim_locked(const struct zone *zone) |
364 | { | 371 | { |
365 | return test_bit(ZONE_RECLAIM_LOCKED, &zone->flags); | 372 | return test_bit(ZONE_RECLAIM_LOCKED, &zone->flags); |
366 | } | 373 | } |
374 | |||
367 | static inline int zone_is_oom_locked(const struct zone *zone) | 375 | static inline int zone_is_oom_locked(const struct zone *zone) |
368 | { | 376 | { |
369 | return test_bit(ZONE_OOM_LOCKED, &zone->flags); | 377 | return test_bit(ZONE_OOM_LOCKED, &zone->flags); |
diff --git a/mm/vmscan.c b/mm/vmscan.c index d8893dc2d4eb..e1471385d001 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -1108,8 +1108,6 @@ static unsigned long shrink_zone(int priority, struct zone *zone, | |||
1108 | unsigned long nr_to_scan; | 1108 | unsigned long nr_to_scan; |
1109 | unsigned long nr_reclaimed = 0; | 1109 | unsigned long nr_reclaimed = 0; |
1110 | 1110 | ||
1111 | zone_set_flag(zone, ZONE_RECLAIM_LOCKED); | ||
1112 | |||
1113 | /* | 1111 | /* |
1114 | * Add one to `nr_to_scan' just to make sure that the kernel will | 1112 | * Add one to `nr_to_scan' just to make sure that the kernel will |
1115 | * slowly sift through the active list. | 1113 | * slowly sift through the active list. |
@@ -1148,8 +1146,6 @@ static unsigned long shrink_zone(int priority, struct zone *zone, | |||
1148 | } | 1146 | } |
1149 | 1147 | ||
1150 | throttle_vm_writeout(sc->gfp_mask); | 1148 | throttle_vm_writeout(sc->gfp_mask); |
1151 | |||
1152 | zone_clear_flag(zone, ZONE_RECLAIM_LOCKED); | ||
1153 | return nr_reclaimed; | 1149 | return nr_reclaimed; |
1154 | } | 1150 | } |
1155 | 1151 | ||
@@ -1900,6 +1896,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) | |||
1900 | int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) | 1896 | int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) |
1901 | { | 1897 | { |
1902 | int node_id; | 1898 | int node_id; |
1899 | int ret; | ||
1903 | 1900 | ||
1904 | /* | 1901 | /* |
1905 | * Zone reclaim reclaims unmapped file backed pages and | 1902 | * Zone reclaim reclaims unmapped file backed pages and |
@@ -1917,13 +1914,13 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) | |||
1917 | <= zone->min_slab_pages) | 1914 | <= zone->min_slab_pages) |
1918 | return 0; | 1915 | return 0; |
1919 | 1916 | ||
1917 | if (zone_is_all_unreclaimable(zone)) | ||
1918 | return 0; | ||
1919 | |||
1920 | /* | 1920 | /* |
1921 | * Avoid concurrent zone reclaims, do not reclaim in a zone that does | 1921 | * Do not scan if the allocation should not be delayed. |
1922 | * not have reclaimable pages and if we should not delay the allocation | ||
1923 | * then do not scan. | ||
1924 | */ | 1922 | */ |
1925 | if (!(gfp_mask & __GFP_WAIT) || zone_is_all_unreclaimable(zone) || | 1923 | if (!(gfp_mask & __GFP_WAIT) || (current->flags & PF_MEMALLOC)) |
1926 | zone_is_reclaim_locked(zone) || (current->flags & PF_MEMALLOC)) | ||
1927 | return 0; | 1924 | return 0; |
1928 | 1925 | ||
1929 | /* | 1926 | /* |
@@ -1935,6 +1932,12 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) | |||
1935 | node_id = zone_to_nid(zone); | 1932 | node_id = zone_to_nid(zone); |
1936 | if (node_state(node_id, N_CPU) && node_id != numa_node_id()) | 1933 | if (node_state(node_id, N_CPU) && node_id != numa_node_id()) |
1937 | return 0; | 1934 | return 0; |
1938 | return __zone_reclaim(zone, gfp_mask, order); | 1935 | |
1936 | if (zone_test_and_set_flag(zone, ZONE_RECLAIM_LOCKED)) | ||
1937 | return 0; | ||
1938 | ret = __zone_reclaim(zone, gfp_mask, order); | ||
1939 | zone_clear_flag(zone, ZONE_RECLAIM_LOCKED); | ||
1940 | |||
1941 | return ret; | ||
1939 | } | 1942 | } |
1940 | #endif | 1943 | #endif |