diff options
author | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | 2010-03-15 00:34:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-17 21:43:47 -0400 |
commit | e9e58a4ec3b1086d1ed8c915311aef1ae55454fd (patch) | |
tree | a500ec01cce13fa17f2400ac57f4ad36f4d37bca | |
parent | a3d3203e4bb40f253b1541e310dc0f9305be7c84 (diff) |
memcg: avoid use cmpxchg in swap cgroup maintainance
swap_cgroup uses 2bytes data and uses cmpxchg in a new operation. 2byte
cmpxchg/xchg is not available on some archs. This patch replaces
cmpxchg/xchg with operations under lock.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Reported-by: Sachin Sant <sachinp@in.ibm.com> wrote:
Acked-by: Balbir Singh <balbir@in.ibm.com>
Acked-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | mm/page_cgroup.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c index 3dd88539a0e6..6c0081441a32 100644 --- a/mm/page_cgroup.c +++ b/mm/page_cgroup.c | |||
@@ -284,6 +284,7 @@ static DEFINE_MUTEX(swap_cgroup_mutex); | |||
284 | struct swap_cgroup_ctrl { | 284 | struct swap_cgroup_ctrl { |
285 | struct page **map; | 285 | struct page **map; |
286 | unsigned long length; | 286 | unsigned long length; |
287 | spinlock_t lock; | ||
287 | }; | 288 | }; |
288 | 289 | ||
289 | struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES]; | 290 | struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES]; |
@@ -353,16 +354,22 @@ unsigned short swap_cgroup_cmpxchg(swp_entry_t ent, | |||
353 | struct swap_cgroup_ctrl *ctrl; | 354 | struct swap_cgroup_ctrl *ctrl; |
354 | struct page *mappage; | 355 | struct page *mappage; |
355 | struct swap_cgroup *sc; | 356 | struct swap_cgroup *sc; |
357 | unsigned long flags; | ||
358 | unsigned short retval; | ||
356 | 359 | ||
357 | ctrl = &swap_cgroup_ctrl[type]; | 360 | ctrl = &swap_cgroup_ctrl[type]; |
358 | 361 | ||
359 | mappage = ctrl->map[idx]; | 362 | mappage = ctrl->map[idx]; |
360 | sc = page_address(mappage); | 363 | sc = page_address(mappage); |
361 | sc += pos; | 364 | sc += pos; |
362 | if (cmpxchg(&sc->id, old, new) == old) | 365 | spin_lock_irqsave(&ctrl->lock, flags); |
363 | return old; | 366 | retval = sc->id; |
367 | if (retval == old) | ||
368 | sc->id = new; | ||
364 | else | 369 | else |
365 | return 0; | 370 | retval = 0; |
371 | spin_unlock_irqrestore(&ctrl->lock, flags); | ||
372 | return retval; | ||
366 | } | 373 | } |
367 | 374 | ||
368 | /** | 375 | /** |
@@ -383,13 +390,17 @@ unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id) | |||
383 | struct page *mappage; | 390 | struct page *mappage; |
384 | struct swap_cgroup *sc; | 391 | struct swap_cgroup *sc; |
385 | unsigned short old; | 392 | unsigned short old; |
393 | unsigned long flags; | ||
386 | 394 | ||
387 | ctrl = &swap_cgroup_ctrl[type]; | 395 | ctrl = &swap_cgroup_ctrl[type]; |
388 | 396 | ||
389 | mappage = ctrl->map[idx]; | 397 | mappage = ctrl->map[idx]; |
390 | sc = page_address(mappage); | 398 | sc = page_address(mappage); |
391 | sc += pos; | 399 | sc += pos; |
392 | old = xchg(&sc->id, id); | 400 | spin_lock_irqsave(&ctrl->lock, flags); |
401 | old = sc->id; | ||
402 | sc->id = id; | ||
403 | spin_unlock_irqrestore(&ctrl->lock, flags); | ||
393 | 404 | ||
394 | return old; | 405 | return old; |
395 | } | 406 | } |
@@ -441,6 +452,7 @@ int swap_cgroup_swapon(int type, unsigned long max_pages) | |||
441 | mutex_lock(&swap_cgroup_mutex); | 452 | mutex_lock(&swap_cgroup_mutex); |
442 | ctrl->length = length; | 453 | ctrl->length = length; |
443 | ctrl->map = array; | 454 | ctrl->map = array; |
455 | spin_lock_init(&ctrl->lock); | ||
444 | if (swap_cgroup_prepare(type)) { | 456 | if (swap_cgroup_prepare(type)) { |
445 | /* memory shortage */ | 457 | /* memory shortage */ |
446 | ctrl->map = NULL; | 458 | ctrl->map = NULL; |