Skip to content
  • Jack Miller's avatar
    shm: make exit_shm work proportional to task activity · ab602f79
    Jack Miller authored
    This is small set of patches our team has had kicking around for a few
    versions internally that fixes tasks getting hung on shm_exit when there
    are many threads hammering it at once.
    
    Anton wrote a simple test to cause the issue:
    
      http://ozlabs.org/~anton/junkcode/bust_shm_exit.c
    
    
    
    Before applying this patchset, this test code will cause either hanging
    tracebacks or pthread out of memory errors.
    
    After this patchset, it will still produce output like:
    
      root@somehost:~# ./bust_shm_exit 1024 160
      ...
      INFO: rcu_sched detected stalls on CPUs/tasks: {} (detected by 116, t=2111 jiffies, g=241, c=240, q=7113)
      INFO: Stall ended before state dump start
      ...
    
    But the task will continue to run along happily, so we consider this an
    improvement over hanging, even if it's a bit noisy.
    
    This patch (of 3):
    
    exit_shm obtains the ipc_ns shm rwsem for write and holds it while it
    walks every shared memory segment in the namespace.  Thus the amount of
    work is related to the number of shm segments in the namespace not the
    number of segments that might need to be cleaned.
    
    In addition, this occurs after the task has been notified the thread has
    exited, so the number of tasks waiting for the ns shm rwsem can grow
    without bound until memory is exausted.
    
    Add a list to the task struct of all shmids allocated by this task.  Init
    the list head in copy_process.  Use the ns->rwsem for locking.  Add
    segments after id is added, remove before removing from id.
    
    On unshare of NEW_IPCNS orphan any ids as if the task had exited, similar
    to handling of semaphore undo.
    
    I chose a define for the init sequence since its a simple list init,
    otherwise it would require a function call to avoid include loops between
    the semaphore code and the task struct.  Converting the list_del to
    list_del_init for the unshare cases would remove the exit followed by
    init, but I left it blow up if not inited.
    
    Signed-off-by: default avatarMilton Miller <miltonm@bga.com>
    Signed-off-by: default avatarJack Miller <millerjo@us.ibm.com>
    Cc: Davidlohr Bueso <davidlohr@hp.com>
    Cc: Manfred Spraul <manfred@colorfullife.com>
    Cc: Anton Blanchard <anton@samba.org>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    ab602f79