24 Jul, 2006

1 commit

  • Fix ABBA deadlock between lock_cpu_hotplug() and the cpuset
    callback_mutex lock.

    It only happens on cpu_exclusive cpusets, due to the dynamic
    sched domain code trying to take the cpu hotplug lock inside
    the cpuset callback_mutex lock.

    This bug has apparently been here for several months, but didn't
    get hit until the right customer load on a large system.

    This fix appears right from inspection, but it will take a few
    more days running it on that customers workload to be confident
    we nailed it. We don't have any other reproducible test case.

    The cpu_hotplug_lock() tends to cover large runs of code.
    The other places that hold both that lock and the cpuset callback
    mutex lock always nest the cpuset lock inside the hotplug lock.
    This place tries to do the reverse, risking an ABBA deadlock.

    This is in the cpuset_rmdir() code, where we:
    * take the callback_mutex lock
    * mark the cpuset CS_REMOVED
    * call update_cpu_domains for cpu_exclusive cpusets
    * in that call, take the cpu_hotplug lock if the
    cpuset is marked for removal.

    Thanks to Jack Steiner for identifying this deadlock.

    The fix is to tear down the dynamic sched domain before we grab
    the cpuset callback_mutex lock. This way, the two locks are
    serialized, with the hotplug lock taken and released before
    trying for the cpuset lock.

    I suspect that this bug was introduced when I changed the
    cpuset locking from one lock to two. The dynamic sched domain
    dependency on cpu_exclusive cpusets and its hotplug hooks were
    added to this code earlier, when cpusets had only a single lock.
    It may well have been fine then.

    Signed-off-by: Paul Jackson
    Signed-off-by: Linus Torvalds

    Paul Jackson
     

01 Jul, 2006

2 commits


27 Jun, 2006

2 commits

  • Incrementally update my proc-dont-lock-task_structs-indefinitely patches so
    that they work with struct pid instead of struct task_ref.

    Mostly this is a straight 1-1 substitution.

    Signed-off-by: Eric W. Biederman
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric W. Biederman
     
  • Every inode in /proc holds a reference to a struct task_struct. If a
    directory or file is opened and remains open after the the task exits this
    pinning continues. With 8K stacks on a 32bit machine the amount pinned per
    file descriptor is about 10K.

    Normally I would figure a reasonable per user process limit is about 100
    processes. With 80 processes, with a 1000 file descriptors each I can trigger
    the 00M killer on a 32bit kernel, because I have pinned about 800MB of useless
    data.

    This patch replaces the struct task_struct pointer with a pointer to a struct
    task_ref which has a struct task_struct pointer. The so the pinning of dead
    tasks does not happen.

    The code now has to contend with the fact that the task may now exit at any
    time. Which is a little but not muh more complicated.

    With this change it takes about 1000 processes each opening up 1000 file
    descriptors before I can trigger the OOM killer. Much better.

    [mlp@google.com: task_mmu small fixes]
    Signed-off-by: Eric W. Biederman
    Cc: Trond Myklebust
    Cc: Paul Jackson
    Cc: Oleg Nesterov
    Cc: Albert Cahalan
    Signed-off-by: Prasanna Meda
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric W. Biederman
     

23 Jun, 2006

2 commits

  • Add a security hook call to enable security modules to control the ability
    to attach a task to a cpuset. While limited control over this operation is
    possible via permission checks on the pseudo fs interface, those checks are
    not sufficient to control access to the target task, which is looked up in
    this function. The existing task_setscheduler hook is re-used for this
    operation since this falls under the same class of operations.

    Signed-off-by: David Quigley
    Acked-by: Stephen Smalley
    Signed-off-by: James Morris
    Acked-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Quigley
     
  • Extend the get_sb() filesystem operation to take an extra argument that
    permits the VFS to pass in the target vfsmount that defines the mountpoint.

    The filesystem is then required to manually set the superblock and root dentry
    pointers. For most filesystems, this should be done with simple_set_mnt()
    which will set the superblock pointer and then set the root dentry to the
    superblock's s_root (as per the old default behaviour).

    The get_sb() op now returns an integer as there's now no need to return the
    superblock pointer.

    This patch permits a superblock to be implicitly shared amongst several mount
    points, such as can be done with NFS to avoid potential inode aliasing. In
    such a case, simple_set_mnt() would not be called, and instead the mnt_root
    and mnt_sb would be set directly.

    The patch also makes the following changes:

    (*) the get_sb_*() convenience functions in the core kernel now take a vfsmount
    pointer argument and return an integer, so most filesystems have to change
    very little.

    (*) If one of the convenience function is not used, then get_sb() should
    normally call simple_set_mnt() to instantiate the vfsmount. This will
    always return 0, and so can be tail-called from get_sb().

    (*) generic_shutdown_super() now calls shrink_dcache_sb() to clean up the
    dcache upon superblock destruction rather than shrink_dcache_anon().

    This is required because the superblock may now have multiple trees that
    aren't actually bound to s_root, but that still need to be cleaned up. The
    currently called functions assume that the whole tree is rooted at s_root,
    and that anonymous dentries are not the roots of trees which results in
    dentries being left unculled.

    However, with the way NFS superblock sharing are currently set to be
    implemented, these assumptions are violated: the root of the filesystem is
    simply a dummy dentry and inode (the real inode for '/' may well be
    inaccessible), and all the vfsmounts are rooted on anonymous[*] dentries
    with child trees.

    [*] Anonymous until discovered from another tree.

    (*) The documentation has been adjusted, including the additional bit of
    changing ext2_* into foo_* in the documentation.

    [akpm@osdl.org: convert ipath_fs, do other stuff]
    Signed-off-by: David Howells
    Acked-by: Al Viro
    Cc: Nathan Scott
    Cc: Roland Dreier
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Howells
     

22 May, 2006

2 commits

  • It's too easy to incorrectly call cpuset_zone_allowed() in an atomic
    context without __GFP_HARDWALL set, and when done, it is not noticed until
    a tight memory situation forces allocations to be tried outside the current
    cpuset.

    Add a 'might_sleep_if()' check, to catch this earlier on, instead of
    waiting for a similar check in the mutex_lock() code, which is only rarely
    invoked.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Update the kernel/cpuset.c:cpuset_zone_allowed() comment.

    The rule for when mm/page_alloc.c should call cpuset_zone_allowed()
    was intended to be:

    Don't call cpuset_zone_allowed() if you can't sleep, unless you
    pass in the __GFP_HARDWALL flag set in gfp_flag, which disables
    the code that might scan up ancestor cpusets and sleep.

    The explanation of this rule in the comment above cpuset_zone_allowed() was
    stale, as a result of a restructuring of some __alloc_pages() code in
    November 2005.

    Rewrite that comment ...

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     

01 Apr, 2006

3 commits

  • Fix memory migration so that it works regardless of what cpuset the invoking
    task is in.

    If a task invoked a memory migration, by doing one of:

    1) writing a different nodemask to a cpuset 'mems' file, or

    2) writing a tasks pid to a different cpuset's 'tasks' file,
    where the cpuset had its 'memory_migrate' option turned on, then the
    allocation of the new pages for the migrated task(s) was constrained
    by the invoking tasks cpuset.

    If this task wasn't in a cpuset that allowed the requested memory nodes, the
    memory migration would happen to some other nodes that were in that invoking
    tasks cpuset. This was usually surprising and puzzling behaviour: Why didn't
    the pages move? Why did the pages move -there-?

    To fix this, temporarilly change the invoking tasks 'mems_allowed' task_struct
    field to the nodes the migrating tasks is moving to, so that new pages can be
    allocated there.

    Signed-off-by: Paul Jackson
    Acked-by: Christoph Lameter
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Fix unsafe reference to a tasks mm struct, by moving the reference inside of a
    convenient nearby properly guarded code block.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Fix cpuset comment involving case of a tasks cpuset pointer being NULL.
    Thanks to "the_top_cpuset_hack", this code no longer sees NULL task->cpuset
    pointers.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     

24 Mar, 2006

6 commits

  • Remove a useless variable initialization in cpuset __cpuset_zone_allowed().
    The local variable 'allowed' is unconditionally set before use, later on
    in the code, so does not need to be initialized.

    Not that it seems to matter to the code generated any, as the compiler
    optimizes out the superfluous assignment anyway.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Drop the atomic_t marking on the cpuset static global
    cpuset_mems_generation. Since all access to it is guarded by the global
    manage_mutex, there is no need for further serialization of this value.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Remove a no longer needed test for NULL cpuset pointer, with a little
    comment explaining why the test isn't needed.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • This patch provides the implementation and cpuset interface for an alternative
    memory allocation policy that can be applied to certain kinds of memory
    allocations, such as the page cache (file system buffers) and some slab caches
    (such as inode caches).

    The policy is called "memory spreading." If enabled, it spreads out these
    kinds of memory allocations over all the nodes allowed to a task, instead of
    preferring to place them on the node where the task is executing.

    All other kinds of allocations, including anonymous pages for a tasks stack
    and data regions, are not affected by this policy choice, and continue to be
    allocated preferring the node local to execution, as modified by the NUMA
    mempolicy.

    There are two boolean flag files per cpuset that control where the kernel
    allocates pages for the file system buffers and related in kernel data
    structures. They are called 'memory_spread_page' and 'memory_spread_slab'.

    If the per-cpuset boolean flag file 'memory_spread_page' is set, then the
    kernel will spread the file system buffers (page cache) evenly over all the
    nodes that the faulting task is allowed to use, instead of preferring to put
    those pages on the node where the task is running.

    If the per-cpuset boolean flag file 'memory_spread_slab' is set, then the
    kernel will spread some file system related slab caches, such as for inodes
    and dentries evenly over all the nodes that the faulting task is allowed to
    use, instead of preferring to put those pages on the node where the task is
    running.

    The implementation is simple. Setting the cpuset flags 'memory_spread_page'
    or 'memory_spread_cache' turns on the per-process flags PF_SPREAD_PAGE or
    PF_SPREAD_SLAB, respectively, for each task that is in the cpuset or
    subsequently joins that cpuset. In subsequent patches, the page allocation
    calls for the affected page cache and slab caches are modified to perform an
    inline check for these flags, and if set, a call to a new routine
    cpuset_mem_spread_node() returns the node to prefer for the allocation.

    The cpuset_mem_spread_node() routine is also simple. It uses the value of a
    per-task rotor cpuset_mem_spread_rotor to select the next node in the current
    tasks mems_allowed to prefer for the allocation.

    This policy can provide substantial improvements for jobs that need to place
    thread local data on the corresponding node, but that need to access large
    file system data sets that need to be spread across the several nodes in the
    jobs cpuset in order to fit. Without this patch, especially for jobs that
    might have one thread reading in the data set, the memory allocation across
    the nodes in the jobs cpuset can become very uneven.

    A couple of Copyright year ranges are updated as well. And a couple of email
    addresses that can be found in the MAINTAINERS file are removed.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Replace pairs of calls to , with a single call
    atomic_inc_return, saving a few bytes of source and kernel text.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Since the test_bit() bit operator is boolean (return 0 or 1), the double not
    "!!" operations needed to convert a scalar (zero or not zero) to a boolean are
    not needed.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     

23 Mar, 2006

1 commit

  • convert cpuset.c's callback_sem and manage_sem to mutexes.
    Build and boot tested by Ingo.
    Build, boot, unit and stress tested by pj.

    Signed-off-by: Ingo Molnar
    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Ingo Molnar
     

16 Feb, 2006

1 commit

  • Fix a latent bug in cpuset_exit() handling. If a task tried to allocate
    memory after calling cpuset_exit(), it oops'd in
    cpuset_update_task_memory_state() on a NULL cpuset pointer.

    So set the exiting tasks cpuset to the root cpuset instead of to NULL.

    A distro kernel hit this with an added kernel package that had just such a
    hook (allocating memory) in the exit code path.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     

04 Feb, 2006

1 commit


15 Jan, 2006

2 commits

  • The problem, reported in:

    http://bugzilla.kernel.org/show_bug.cgi?id=5859

    and by various other email messages and lkml posts is that the cpuset hook
    in the oom (out of memory) code can try to take a cpuset semaphore while
    holding the tasklist_lock (a spinlock).

    One must not sleep while holding a spinlock.

    The fix seems easy enough - move the cpuset semaphore region outside the
    tasklist_lock region.

    This required a few lines of mechanism to implement. The oom code where
    the locking needs to be changed does not have access to the cpuset locks,
    which are internal to kernel/cpuset.c only. So I provided a couple more
    cpuset interface routines, available to the rest of the kernel, which
    simple take and drop the lock needed here (cpusets callback_sem).

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Remove the "inline" keyword from a bunch of big functions in the kernel with
    the goal of shrinking it by 30kb to 40kb

    Signed-off-by: Arjan van de Ven
    Signed-off-by: Ingo Molnar
    Acked-by: Jeff Garzik
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Arjan van de Ven
     

10 Jan, 2006

1 commit


09 Jan, 2006

16 commits

  • Some long time ago, dentry struct was carefully tuned so that on 32 bits
    UP, sizeof(struct dentry) was exactly 128, ie a power of 2, and a multiple
    of memory cache lines.

    Then RCU was added and dentry struct enlarged by two pointers, with nice
    results for SMP, but not so good on UP, because breaking the above tuning
    (128 + 8 = 136 bytes)

    This patch reverts this unwanted side effect, by using an union (d_u),
    where d_rcu and d_child are placed so that these two fields can share their
    memory needs.

    At the time d_free() is called (and d_rcu is really used), d_child is known
    to be empty and not touched by the dentry freeing.

    Lockless lookups only access d_name, d_parent, d_lock, d_op, d_flags (so
    the previous content of d_child is not needed if said dentry was unhashed
    but still accessed by a CPU because of RCU constraints)

    As dentry cache easily contains millions of entries, a size reduction is
    worth the extra complexity of the ugly C union.

    Signed-off-by: Eric Dumazet
    Cc: Dipankar Sarma
    Cc: Maneesh Soni
    Cc: Miklos Szeredi
    Cc: "Paul E. McKenney"
    Cc: Ian Kent
    Cc: Paul Jackson
    Cc: Al Viro
    Cc: Christoph Hellwig
    Cc: Trond Myklebust
    Cc: Neil Brown
    Cc: James Morris
    Cc: Stephen Smalley
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric Dumazet
     
  • For systems that aren't using cpusets, but have them CONFIG_CPUSET enabled in
    their kernel (eventually this may be most distribution kernels), this patch
    removes even the minimal rcu_read_lock() from the memory page allocation path.

    Actually, it removes that rcu call for any task that is in the root cpuset
    (top_cpuset), which on systems not actively using cpusets, is all tasks.

    We don't need the rcu check for tasks in the top_cpuset, because the
    top_cpuset is statically allocated, so at no risk of being freed out from
    underneath us.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Mark cpuset global 'number_of_cpusets' as __read_mostly.

    This global is accessed everytime a zone is considered in the zonelist loops
    beneath __alloc_pages, looking for a free memory page. If number_of_cpusets
    is just one, then we can short circuit the mems_allowed check.

    Since this global is read alot on a hot path, and written rarely, it is an
    excellent candidate for __read_mostly.

    Thanks to Christoph Lameter for the suggestion.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Optimize the cpuset impact on page allocation, the most performance critical
    cpuset hook in the kernel.

    On each page allocation, the cpuset hook needs to check for a possible change
    in the current tasks cpuset. It can now handle the common case, of no change,
    without taking any spinlock or semaphore, thanks to RCU.

    Convert a spinlock on the current task to an rcu_read_lock(), saving
    approximately a memory barrier and an atomic op, depending on architecture.

    This is done by adding rcu_assign_pointer() and synchronize_rcu() calls to the
    write side of the task->cpuset pointer, in cpuset.c:attach_task(), to delay
    freeing up a detached cpuset until after any critical sections referencing
    that pointer.

    Thanks to Andi Kleen, Nick Piggin and Eric Dumazet for ideas.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Remove a couple of more lines of code from the cpuset hooks in the page
    allocation code path.

    There was a check for a NULL cpuset pointer in the routine
    cpuset_update_task_memory_state() that was only needed during system boot,
    after the memory subsystem was initialized, before the cpuset subsystem was
    initialized, to catch a NULL task->cpuset pointer.

    Add a cpuset_init_early() routine, just before the mem_init() call in
    init/main.c, that sets up just enough of the init tasks cpuset structure to
    render cpuset_update_task_memory_state() calls harmless.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Given the mechanism in the previous patch to handle rebinding the per-vma
    mempolicies of all tasks in a cpuset that changes its memory placement, it is
    now easier to handle the page migration requirements of such tasks at the same
    time.

    The previous code didn't actually attempt to migrate the pages of the tasks in
    a cpuset whose memory placement changed until the next time each such task
    tried to allocate memory. This was undesirable, as users invoking memory page
    migration exected to happen when the placement changed, not some unspecified
    time later when the task needed more memory.

    It is now trivial to handle the page migration at the same time as the per-vma
    rebinding is done.

    The routine cpuset.c:update_nodemask(), which handles changing a cpusets
    memory placement ('mems') now checks for the special case of being asked to
    write a placement that is the same as before. It was harmless enough before
    to just recompute everything again, even though nothing had changed. But page
    migration is a heavy weight operation - moving pages about. So now it is
    worth avoiding that if asked to move a cpuset to its current location.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Fix more of longstanding bug in cpuset/mempolicy interaction.

    NUMA mempolicies (mm/mempolicy.c) are constrained by the current tasks cpuset
    to just the Memory Nodes allowed by that cpuset. The kernel maintains
    internal state for each mempolicy, tracking what nodes are used for the
    MPOL_INTERLEAVE, MPOL_BIND or MPOL_PREFERRED policies.

    When a tasks cpuset memory placement changes, whether because the cpuset
    changed, or because the task was attached to a different cpuset, then the
    tasks mempolicies have to be rebound to the new cpuset placement, so as to
    preserve the cpuset-relative numbering of the nodes in that policy.

    An earlier fix handled such mempolicy rebinding for mempolicies attached to a
    task.

    This fix rebinds mempolicies attached to vma's (address ranges in a tasks
    address space.) Due to the need to hold the task->mm->mmap_sem semaphore while
    updating vma's, the rebinding of vma mempolicies has to be done when the
    cpuset memory placement is changed, at which time mmap_sem can be safely
    acquired. The tasks mempolicy is rebound later, when the task next attempts
    to allocate memory and notices that its task->cpuset_mems_generation is
    out-of-date with its cpusets mems_generation.

    Because walking the tasklist to find all tasks attached to a changing cpuset
    requires holding tasklist_lock, a spinlock, one cannot update the vma's of the
    affected tasks while doing the tasklist scan. In general, one cannot acquire
    a semaphore (which can sleep) while already holding a spinlock (such as
    tasklist_lock). So a list of mm references has to be built up during the
    tasklist scan, then the tasklist lock dropped, then for each mm, its mmap_sem
    acquired, and the vma's in that mm rebound.

    Once the tasklist lock is dropped, affected tasks may fork new tasks, before
    their mm's are rebound. A kernel global 'cpuset_being_rebound' is set to
    point to the cpuset being rebound (there can only be one; cpuset modifications
    are done under a global 'manage_sem' semaphore), and the mpol_copy code that
    is used to copy a tasks mempolicies during fork catches such forking tasks,
    and ensures their children are also rebound.

    When a task is moved to a different cpuset, it is easier, as there is only one
    task involved. It's mm->vma's are scanned, using the same
    mpol_rebind_policy() as used above.

    It may happen that both the mpol_copy hook and the update done via the
    tasklist scan update the same mm twice. This is ok, as the mempolicies of
    each vma in an mm keep track of what mems_allowed they are relative to, and
    safely no-op a second request to rebind to the same nodes.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Easy little optimization hack to avoid actually having to call
    cpuset_zone_allowed() and check mems_allowed, in the main page allocation
    routine, __alloc_pages(). This saves several CPU cycles per page allocation
    on systems not using cpusets.

    A counter is updated each time a cpuset is created or removed, and whenever
    there is only one cpuset in the system, it must be the root cpuset, which
    contains all CPUs and all Memory Nodes. In that case, when the counter is
    one, all allocations are allowed.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Cleanup, reorganize and make more robust the mempolicy.c code to rebind
    mempolicies relative to the containing cpuset after a tasks memory placement
    changes.

    The real motivator for this cleanup patch is to lay more groundwork for the
    upcoming patch to correctly rebind NUMA mempolicies that are attached to vma's
    after the containing cpuset memory placement changes.

    NUMA mempolicies are constrained by the cpuset their task is a member of.
    When either (1) a task is moved to a different cpuset, or (2) the 'mems'
    mems_allowed of a cpuset is changed, then the NUMA mempolicies have embedded
    node numbers (for MPOL_BIND, MPOL_INTERLEAVE and MPOL_PREFERRED) that need to
    be recalculated, relative to their new cpuset placement.

    The old code used an unreliable method of determining what was the old
    mems_allowed constraining the mempolicy. It just looked at the tasks
    mems_allowed value. This sort of worked with the present code, that just
    rebinds the -task- mempolicy, and leaves any -vma- mempolicies broken,
    referring to the old nodes. But in an upcoming patch, the vma mempolicies
    will be rebound as well. Then the order in which the various task and vma
    mempolicies are updated will no longer be deterministic, and one can no longer
    count on the task->mems_allowed holding the old value for as long as needed.
    It's not even clear if the current code was guaranteed to work reliably for
    task mempolicies.

    So I added a mems_allowed field to each mempolicy, stating exactly what
    mems_allowed the policy is relative to, and updated synchronously and reliably
    anytime that the mempolicy is rebound.

    Also removed a useless wrapper routine, numa_policy_rebind(), and had its
    caller, cpuset_update_task_memory_state(), call directly to the rewritten
    policy_rebind() routine, and made that rebind routine extern instead of
    static, and added a "mpol_" prefix to its name, making it
    mpol_rebind_policy().

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Provide a cpuset_mems_allowed() method, which the sys_migrate_pages() code
    needed, to obtain the mems_allowed vector of a cpuset, and replaced the
    workaround in sys_migrate_pages() to call this new method.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • The important code paths through alloc_pages_current() and alloc_page_vma(),
    by which most kernel page allocations go, both called
    cpuset_update_current_mems_allowed(), which in turn called refresh_mems().
    -Both- of these latter two routines did a tasklock, got the tasks cpuset
    pointer, and checked for out of date cpuset->mems_generation.

    That was a silly duplication of code and waste of CPU cycles on an important
    code path.

    Consolidated those two routines into a single routine, called
    cpuset_update_task_memory_state(), since it updates more than just
    mems_allowed.

    Changed all callers of either routine to call the new consolidated routine.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Fix obscure, never seen in real life, cpuset fork race. The cpuset_fork()
    call in fork.c was setting up the correct task->cpuset pointer after the
    tasklist_lock was dropped, which briefly exposed the newly forked process with
    an unsafe (copied from parent without locks or usage counter increment) cpuset
    pointer.

    In theory, that exposed cpuset pointer could have been pointing at a cpuset
    that was already freed and removed, and in theory another task that had been
    sitting on the tasklist_lock waiting to scan the task list could have raced
    down the entire tasklist, found our new child at the far end, and dereferenced
    that bogus cpuset pointer.

    To fix, setup up the correct cpuset pointer in the new child by calling
    cpuset_fork() before the new task is linked into the tasklist, and with that,
    add a fork failure case, to dereference that cpuset, if the fork fails along
    the way, after cpuset_fork() was called.

    Had to remove a BUG_ON() from cpuset_exit(), because it was no longer valid -
    the call to cpuset_exit() from a failed fork would not have PF_EXITING set.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Restructure code layout of the kernel/cpuset.c update_nodemask() routine,
    removing embedded returns and nested if's in favor of goto completion labels.
    This is being done in anticipation of adding more logic to this routine, which
    will favor the goto style structure.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Four trivial cpuset fixes: remove extra spaces, remove useless initializers,
    mark one __read_mostly.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Provide a simple per-cpuset metric of memory pressure, tracking the -rate-
    that the tasks in a cpuset call try_to_free_pages(), the synchronous
    (direct) memory reclaim code.

    This enables batch managers monitoring jobs running in dedicated cpusets to
    efficiently detect what level of memory pressure that job is causing.

    This is useful both on tightly managed systems running a wide mix of
    submitted jobs, which may choose to terminate or reprioritize jobs that are
    trying to use more memory than allowed on the nodes assigned them, and with
    tightly coupled, long running, massively parallel scientific computing jobs
    that will dramatically fail to meet required performance goals if they
    start to use more memory than allowed to them.

    This patch just provides a very economical way for the batch manager to
    monitor a cpuset for signs of memory pressure. It's up to the batch
    manager or other user code to decide what to do about it and take action.

    ==> Unless this feature is enabled by writing "1" to the special file
    /dev/cpuset/memory_pressure_enabled, the hook in the rebalance
    code of __alloc_pages() for this metric reduces to simply noticing
    that the cpuset_memory_pressure_enabled flag is zero. So only
    systems that enable this feature will compute the metric.

    Why a per-cpuset, running average:

    Because this meter is per-cpuset, rather than per-task or mm, the
    system load imposed by a batch scheduler monitoring this metric is
    sharply reduced on large systems, because a scan of the tasklist can be
    avoided on each set of queries.

    Because this meter is a running average, instead of an accumulating
    counter, a batch scheduler can detect memory pressure with a single
    read, instead of having to read and accumulate results for a period of
    time.

    Because this meter is per-cpuset rather than per-task or mm, the
    batch scheduler can obtain the key information, memory pressure in a
    cpuset, with a single read, rather than having to query and accumulate
    results over all the (dynamically changing) set of tasks in the cpuset.

    A per-cpuset simple digital filter (requires a spinlock and 3 words of data
    per-cpuset) is kept, and updated by any task attached to that cpuset, if it
    enters the synchronous (direct) page reclaim code.

    A per-cpuset file provides an integer number representing the recent
    (half-life of 10 seconds) rate of direct page reclaims caused by the tasks
    in the cpuset, in units of reclaims attempted per second, times 1000.

    Signed-off-by: Paul Jackson
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson
     
  • Finish converting mm/mempolicy.c from bitmaps to nodemasks. The previous
    conversion had left one routine using bitmaps, since it involved a
    corresponding change to kernel/cpuset.c

    Fix that interface by replacing with a simple macro that calls nodes_subset(),
    or if !CONFIG_CPUSET, returns (1).

    Signed-off-by: Paul Jackson
    Cc: Christoph Lameter
    Cc: Andi Kleen
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Paul Jackson