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>

authored by

KAMEZAWA Hiroyuki and committed by
Linus Torvalds
e9e58a4e a3d3203e

+16 -4
+16 -4
mm/page_cgroup.c
··· 284 284 struct swap_cgroup_ctrl { 285 285 struct page **map; 286 286 unsigned long length; 287 + spinlock_t lock; 287 288 }; 288 289 289 290 struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES]; ··· 354 353 struct swap_cgroup_ctrl *ctrl; 355 354 struct page *mappage; 356 355 struct swap_cgroup *sc; 356 + unsigned long flags; 357 + unsigned short retval; 357 358 358 359 ctrl = &swap_cgroup_ctrl[type]; 359 360 360 361 mappage = ctrl->map[idx]; 361 362 sc = page_address(mappage); 362 363 sc += pos; 363 - if (cmpxchg(&sc->id, old, new) == old) 364 - return old; 364 + spin_lock_irqsave(&ctrl->lock, flags); 365 + retval = sc->id; 366 + if (retval == old) 367 + sc->id = new; 365 368 else 366 - return 0; 369 + retval = 0; 370 + spin_unlock_irqrestore(&ctrl->lock, flags); 371 + return retval; 367 372 } 368 373 369 374 /** ··· 390 383 struct page *mappage; 391 384 struct swap_cgroup *sc; 392 385 unsigned short old; 386 + unsigned long flags; 393 387 394 388 ctrl = &swap_cgroup_ctrl[type]; 395 389 396 390 mappage = ctrl->map[idx]; 397 391 sc = page_address(mappage); 398 392 sc += pos; 399 - old = xchg(&sc->id, id); 393 + spin_lock_irqsave(&ctrl->lock, flags); 394 + old = sc->id; 395 + sc->id = id; 396 + spin_unlock_irqrestore(&ctrl->lock, flags); 400 397 401 398 return old; 402 399 } ··· 452 441 mutex_lock(&swap_cgroup_mutex); 453 442 ctrl->length = length; 454 443 ctrl->map = array; 444 + spin_lock_init(&ctrl->lock); 455 445 if (swap_cgroup_prepare(type)) { 456 446 /* memory shortage */ 457 447 ctrl->map = NULL;