Optionally inherit mlockall() semantics across fork()/exec()
Subsystems (6)
RFC PATCH 1/1 Optionally inherit mlockall() semantics across fork()/exec()
Add support for mlockall(MCL_INHERIT):
MCL_CURRENT|MCL_INHERIT - inherit memory locks across fork() MCL_FUTURE|MCL_INHERIT - inherit "MCL_FUTURE" semantics across fork() and exec().
In support of a "lock prefix command"--e.g., mlock <cmd> <args> ... Together with Christoph Lameter's patch to keep mlocked pages off the LRU, this will allow users/admins to lock down applications without modifying them, keeping their pages off the LRU and out of consideration for reclaim.
Define MCL_INHERIT in <asm/mman.h>.
Add an int to mm_struct to remember inheritance of future locks.
TODO: use a bit flag in some other member? For now, slot it in where we might have some padding on 64-bit systems.
sys_mlockall(): Allow MCL_INHERIT in flags.
do_mlockall(): Set mcl_inherit non-zero in mm_struct if
MCL_INHERIT set; otherwise, zero mcl_inherit [munlockall()].
Note: mlockall() w/o MCL_INHERIT will also
turn off future lock inheritance.
dup_mm(): Inherit vm locks and mcl_inherit itself
over fork() if mcl_inherit set in parent's mm_struct.
mm_init(): Inherit the MCL_INHERIT and MCL_FUTURE
state. This will propagate across exec() via exec_mmap().
load_elf_binary(): Propagate VM_LOCKED in def_flags if mcl_inherit
set in current->mm. [Why does the elf loader muck with def_flags? Other binary loaders don't. Shouldn't this be in more generic code?]
Note: A similar feature was implemented in at least one real time enhanced Unix back in the 90's [Concurrent Computer's MaxOS]. Jeff Sharkey at Montana State developed a similar patch for Linux [see: http://www.cs.montana.edu/~jsharkey/cs518/jsharkey-final.ppt],
but apparently he never submitted it.
Example "lock prefix command" at:
http://free.linux.hp.com/~lts/Tools/mlock-latest.tar.gz
TODO: man page enhancement, if patch accepted.
fs/binfmt_elf.c | 4 ++++ include/asm/mman.h | 1 + include/linux/sched.h | 1 + kernel/fork.c | 11 +++++++++-- mm/mlock.c | 5 +++-- 5 files changed, 18 insertions(+), 4 deletions(-)
include/asm/mman.h +1 -0
@@ -21,6 +21,7 @@#define MCL_CURRENT 1/* lock all current mappings */ #define MCL_FUTURE 2/* lock all future mappings */ +#define MCL_INHERIT 4/* inherit '_FUTURE across fork/exec */ #ifdef __KERNEL__#ifndef __ASSEMBLY__
include/linux/sched.h +1 -0
@@ -325,6 +325,7 @@ struct mm_struct {atomic_t mm_users;/* How many users with user space? */ atomic_t mm_count;/* How many references to "struct mm_struct" (users count as 1) */ int map_count;/* number of VMAs */ +int mcl_inherit;/* inherit future locks */ struct rw_semaphore mmap_sem;spinlock_t page_table_lock;/* Protects page tables and some counters */
mm/mlock.c +3 -2
@@ -184,7 +184,8 @@ static int do_mlockall(int flags)if (flags &MCL_FUTURE ) def_flags =VM_LOCKED ; current->mm->def_flags = def_flags; -if (flags ==MCL_FUTURE ) + current->mm->mcl_inherit = !!(flags &MCL_INHERIT ); +if ((flags & ~MCL_INHERIT ) ==MCL_FUTURE ) goto out;for (vma = current->mm->mmap; vma ; vma = prev->vm_next) {
@@ -206,7 +207,7 @@ asmlinkage long sys_mlockall(int flags)unsigned long lock_limit;int ret = -EINVAL ; -if (!flags || (flags & ~(MCL_CURRENT |MCL_FUTURE ))) +if (!flags || (flags & ~(MCL_CURRENT |MCL_FUTURE |MCL_INHERIT ))) goto out; ret = -EPERM ;
kernel/fork.c +9 -2
@@ -249,7 +249,8 @@ static inline int dup_mmap(struct mm_strif (IS_ERR (pol)) goto fail_nomem_policy;vma_set_policy (tmp, pol); - tmp->vm_flags &= ~VM_LOCKED ; +if (!mm->mcl_inherit) + tmp->vm_flags &= ~VM_LOCKED ; tmp->vm_mm = mm; tmp->vm_next =NULL ;anon_vma_link (tmp);
@@ -330,6 +331,8 @@ static inline void mm_free_pgd(struct mmstatic struct mm_struct *mm_init (struct mm_struct * mm) { +unsigned long def_flags =0 ; +atomic_set (&mm->mm_users,1 );atomic_set (&mm->mm_count,1 );init_rwsem (&mm->mmap_sem);
@@ -343,9 +346,13 @@ static struct mm_struct * mm_init(struct mm->ioctx_list =NULL ; mm->free_area_cache =TASK_UNMAPPED_BASE ; mm->cached_hole_size = ~0UL ; +if (current->mm && current->mm->mcl_inherit) { + mm->mcl_inherit = current->mm->mcl_inherit; + def_flags = current->mm->def_flags &VM_LOCKED ; + }if (likely (!mm_alloc_pgd (mm))) { - mm->def_flags =0 ; + mm->def_flags = def_flags;return mm; }free_mm (mm);
fs/binfmt_elf.c +4 -0
@@ -766,6 +766,10 @@ static int load_elf_binary(struct linux_ } } +/* Optionally inherit MCL_FUTURE state before destroying old mm */ +if (current->mm && current->mm->mcl_inherit) + def_flags = current->mm->def_flags &VM_LOCKED ; +/* Flush all traces of the currently running executable */ retval =flush_old_exec (bprm);if (retval)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 1 line · Lee Schermerhorn
Add an int to
mm_structto remember inheritance of future locks.
Should that not go into the task_struct rather than into mm_struct? If you run your gizmo on a thread then all other threads of the process will also be pinned.
Or put it into the vma like VM_MLOCK and inherit it when vmas are copied.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 7 lines · Christoph Lameter
Quoted 1 line · Lee Schermerhorn
Add an int to
mm_structto remember inheritance of future locks.Should that not go into the
task_structrather than intomm_struct? If you run your gizmo on a thread then all other threads of the process will also be pinned.
Well, you currently can't run it on a thread--i.e., no way to affect an existing task/thread. It only works when launching an application. I have considered how to apply it to a running process, but I wanted to float this proposal first.
The semantics of mlockall(), whether you use the '_CURRENT and/or the '_FUTURE flag, apply to the entire address space of the process. [See
http://www.opengroup.org/onlinepubs/7990989775/xsh/mlockall.html] The patch enables inheritance of these semantics across fork() [CURRENT] and exec() [FUTURE].
Quoted 2 lines
Or put it into the vma like
VM_MLOCKand inherit it when vmas are copied.
Again, mlockall(MCL_FUTURE) sets def_flags in the mm_struct so that it applies to the entire address space. Without this patch, dup_mm() unconditionally removes the VM_LOCKED flags from vmas, in keeping with the specified semantics of fork(). The MCL_INHERIT flag overrides this particular semantic, and leaves the VM_LOCKED flag untouched in the duplicated vmas.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines · Lee Schermerhorn
The semantics of
mlockall(), whether you use the '_CURRENTand/or the '_FUTUREflag, apply to the entire address space of the process. [See
http://www.opengroup.org/onlinepubs/7990989775/xsh/mlockall.html] The patch enables inheritance of these semantics acrossfork()[CURRENT] andexec()[FUTURE].
Ahh. I see. Then setting a flags in the vma would work? There is already logic to handle VM_LOCKED in mm/mlock.c and we keep on checking vma->vm_flags. Maybe add VM_LOCKED_FUTURE?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>