Skip to contentSkip to conversation

- support inheritance of mlocks across fork/exec

PATCH/RFC In review Lee Schermerhorn 6 participants 18 messages Nov 24, 2008 – Jun 5, 2009

Subsystems (9)
lore
Share & tools
lore
#0 lore raw

PATCH/RFC - support inheritance of mlocks across fork/exec

Against; 2.6.28-rc5-mmotm-081121

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):
MCL_CURRENT|MCL_INHERIT - inherit memory locks across fork() MCL_FUTURE|MCL_INHERIT - inherit "MCL_FUTURE" semantics across fork() and exec().
MCL_RECURSIVE - inherit across future generations.

In support of a "lock prefix command"--e.g., mlock <cmd> <args> ...

Together with patches to keep mlocked pages off the LRU, this will allow users/admins to lock down applications without modifying them, if their RLIMIT_MEMLOCK is sufficiently large, keeping their pages off the LRU and out of consideration for reclaim.

Potentially useful in real-time environments to force prefaulting and residency for applications that don't mlock themselves.

Jeff Sharkey at Montana State developed a similar patch for Linux [link no longer accessible], but apparently he never submitted the patch.

I submitted an earlier version of this patch around a year ago. I resurrected it to test the unevictable lru/mlocked pages patches-- e.g., by "mlock -r make -j<N*nr_cpus> all". This did shake out a few races and vmstat accounting bugs, but NOT something I'd recommend as general practice--for kernel builds, that is.

Define MCL_INHERIT, MCL_RECURSIVE in <asm-*/mman.h>.
+ x86 and ia64 versions included.
+ other arch can/will be created, if this patch deemed merge-worthy.

Similarly, I'll provide kernel man page update if/when needed.

Example "lock prefix command" in Documentation/vm/mlock.c

 Documentation/vm/mlock.c     |  149 +++++++++++++++++++++++++++++++++++++++++++
 arch/ia64/include/asm/mman.h |    2 
 arch/x86/include/asm/mman.h  |    3 
 fs/binfmt_elf.c              |    9 ++
 include/linux/mm_types.h     |    2 
 kernel/fork.c                |   15 +++-
 mm/mlock.c                   |   14 ++--
 7 files changed, 186 insertions(+), 8 deletions(-)
arch/ia64/include/asm/mman.h +2 -0
Index: linux-2.6.28-rc5-mmotm-081121/arch/ia64/include/asm/mman.h
===================================================================
@@ -21,6 +21,8 @@
 
 #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 */
+#define MCL_RECURSIVE	8		/* inherit '_FUTURE recursively */
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
mm/mlock.c +9 -5
Index: linux-2.6.28-rc5-mmotm-081121/mm/mlock.c
===================================================================
@@ -572,15 +572,18 @@ asmlinkage long sys_munlock(unsigned lon
 static int do_mlockall(int flags)
 {
 	struct vm_area_struct * vma, * prev = NULL;
+	struct mm_struct *mm = current->mm;
 	unsigned int def_flags = 0;
 
 	if (flags & MCL_FUTURE)
-		def_flags = VM_LOCKED;
-	current->mm->def_flags = def_flags;
-	if (flags == MCL_FUTURE)
+		def_flags = VM_LOCKED;;
+	mm->def_flags = def_flags;
+	if (flags & MCL_INHERIT)
+		mm->mcl_inherit = flags & (MCL_INHERIT | MCL_RECURSIVE);
+	if ((flags & ~(MCL_INHERIT | MCL_RECURSIVE)) == MCL_FUTURE)
 		goto out;
 
-	for (vma = current->mm->mmap; vma ; vma = prev->vm_next) {
+	for (vma = mm->mmap; vma ; vma = prev->vm_next) {
 		unsigned int newflags;
 
 		newflags = vma->vm_flags | VM_LOCKED;
@@ -599,7 +602,8 @@ 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 | MCL_RECURSIVE)))
 		goto out;
 
 	ret = -EPERM;
kernel/fork.c +12 -3
Index: linux-2.6.28-rc5-mmotm-081121/kernel/fork.c
===================================================================
@@ -274,7 +274,8 @@ static int dup_mmap(struct mm_struct *mm
 	 */
 	down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING);
 
-	mm->locked_vm = 0;
+	if (!mm->mcl_inherit)
+		mm->locked_vm = 0;
 	mm->mmap = NULL;
 	mm->mmap_cache = NULL;
 	mm->free_area_cache = oldmm->mmap_base;
@@ -312,7 +313,8 @@ static int dup_mmap(struct mm_struct *mm
 		if (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);
@@ -402,6 +404,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLO
 
 static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
 {
+	unsigned long def_flags = 0;
+
 	atomic_set(&mm->mm_users, 1);
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);
@@ -418,9 +422,14 @@ static struct mm_struct * mm_init(struct
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->cached_hole_size = ~0UL;
 	mm_init_owner(mm, p);
+	if (current->mm && current->mm->mcl_inherit) {
+		def_flags = current->mm->def_flags & VM_LOCKED;
+		if (mm->mcl_inherit & MCL_RECURSIVE)
+			mm->mcl_inherit  = current->mm->mcl_inherit;
+	}
 
 	if (likely(!mm_alloc_pgd(mm))) {
-		mm->def_flags = 0;
+		mm->def_flags = def_flags;
 		mmu_notifier_mm_init(mm);
 		return mm;
 	}
fs/binfmt_elf.c +9 -0
Index: linux-2.6.28-rc5-mmotm-081121/fs/binfmt_elf.c
===================================================================
@@ -585,6 +585,7 @@ static int load_elf_binary(struct linux_
 	unsigned long reloc_func_desc = 0;
 	int executable_stack = EXSTACK_DEFAULT;
 	unsigned long def_flags = 0;
+	int mcl_inherit = 0;
 	struct {
 		struct elfhdr elf_ex;
 		struct elfhdr interp_elf_ex;
@@ -749,6 +750,13 @@ static int load_elf_binary(struct linux_
 		SET_PERSONALITY(loc->elf_ex);
 	}
 
+	/* Optionally inherit MCL_FUTURE state before destroying old mm */
+	if (current->mm && current->mm->mcl_inherit) {
+		def_flags = current->mm->def_flags & VM_LOCKED;
+		if (current->mm->mcl_inherit & MCL_RECURSIVE)
+			mcl_inherit  = current->mm->mcl_inherit;
+	}
+
 	/* Flush all traces of the currently running executable */
 	retval = flush_old_exec(bprm);
 	if (retval)
@@ -757,6 +765,7 @@ static int load_elf_binary(struct linux_
 	/* OK, This is the point of no return */
 	current->flags &= ~PF_FORKNOEXEC;
 	current->mm->def_flags = def_flags;
+	current->mm->mcl_inherit = mcl_inherit;
 
 	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
 	   may depend on the personality.  */
arch/x86/include/asm/mman.h +3 -0
Index: linux-2.6.28-rc5-mmotm-081121/arch/x86/include/asm/mman.h
===================================================================
@@ -16,5 +16,8 @@
 
 #define MCL_CURRENT	1		/* lock all current mappings */
 #define MCL_FUTURE	2		/* lock all future mappings */
+#define MCL_INHERIT	4		/* inherit mlocks across fork */
+					/* inherit '_FUTURE flag across fork/exec */
+#define MCL_RECURSIVE	8		/* inherit mlocks recursively */
 
 #endif /* _ASM_X86_MMAN_H */
include/linux/mm_types.h +2 -0
Index: linux-2.6.28-rc5-mmotm-081121/include/linux/mm_types.h
===================================================================
@@ -235,6 +235,8 @@ struct mm_struct {
 	unsigned int token_priority;
 	unsigned int last_interval;
 
+	int mcl_inherit;		/* inherit current/future locks */
+
 	unsigned long flags; /* Must use atomic bitops to access the bits */
 
 	struct core_state *core_state; /* coredumping support */
Documentation/vm/mlock.c new file +149 -0

149 lines not on this page · raw message

--
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>

#1 lore raw
Quoted 11 lines

PATCH/RFC - support inheritance of mlocks across fork/exec

Against; 2.6.28-rc5-mmotm-081121

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):
MCL_CURRENT|MCL_INHERIT - inherit memory locks across fork() MCL_FUTURE|MCL_INHERIT - inherit "MCL_FUTURE" semantics across fork() and exec().
MCL_RECURSIVE - inherit across future generations.

In support of a "lock prefix command"--e.g., mlock <cmd> <args> ...

I don't review yet, but I believe this patch is useful for mlock related kernel test.

I plan to review it tommorow.
thanks.

--
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>

Acked-by
#2 lore raw
In reply to Lee Schermerhorn
Quoted 1 line · Lee Schermerhorn

PATCH/RFC - support inheritance of mlocks across fork/exec

Looks like it could be useful.

Quoted 1 line
Signature · 7 lines
All Rights Reversed

--
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>
maintainer
#3 lore raw
In reply to Lee Schermerhorn
Quoted 1 line · On Mon, 24 Nov 2008 16:21:46 -0500 Lee Schermerhorn <[email protected]>…

PATCH/RFC - support inheritance of mlocks across fork/exec

Linux actually used to do this by mistake. We fixed it in 2.3.<mumble>, iirc.

Quoted 9 lines

Against; 2.6.28-rc5-mmotm-081121

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):
MCL_CURRENT|MCL_INHERIT - inherit memory locks across fork() MCL_FUTURE|MCL_INHERIT - inherit "MCL_FUTURE" semantics across fork() and exec().
MCL_RECURSIVE - inherit across future generations.

In support of a "lock prefix command"--e.g., mlock <cmd> <args> ...

I spent some time scratching my head over what "MCL_RECURSIVE - inherit across future generations" means, then decided that I shouldn't need to scratch.

This patch should get wider attention than just linux-mm denizens, methinks.

So can you please beef up the MCL_RECURSIVE description, then resend the patch, also cc'ing [email protected], [email protected] and [email protected]?

Thanks.

--
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>

#4 lore raw

PATCH 1/1 - support inheritance of mlocks across fork/exec V2

Against; 2.6.28-rc7-mmotm-081203

V02: rework vetting of flags argument as suggested by
Kosaki Motohiro.
enhance description as requested by Andrew Morton.

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):

MCL_CURRENT[|MCL_FUTURE]|MCL_INHERIT - inherit memory locks
[vmas' VM_LOCKED flags] across fork(), and inherit MCL_FUTURE behavior [mm's def_flags] across fork() and exec(). Behaves as if child and/or new task called mlockall(MCL_CURRENT|MCL_FUTURE) as first instruction.

MCL_RECURSIVE - inherit MCL_CURRENT|MCL_FUTURE|MCL_INHERIT
[vmas' VM_LOCKED flags for fork() and mm's def_flags and mcl_inherit across fork() and exec()] for all future generations of calling process's descendants. Behaves as if child and/or new task called mlockall(MCL_CURRENT|MCL_FUTURE|MCL_INHERIT|MCL_RECURSIVE) as the first instruction.

In support of a "lock prefix command"--e.g., mlock <cmd> <args> ... Analogous to taskset(1) for cpu affinity or numactl(8) for numa memory policy.

Together with patches to keep mlocked pages off the LRU, this will allow users/admins to lock down applications without modifying them, if their RLIMIT_MEMLOCK is sufficiently large, keeping their pages off the LRU and out of consideration for reclaim.

Potentially useful, as well, in real-time environments to force prefaulting and residency for applications that don't mlock themselves.

Jeff Sharkey at Montana State developed a similar patch for Linux [link no longer accessible], but apparently he never submitted the patch.

I submitted an earlier version of this patch around a year ago. I resurrected it to test the unevictable lru/mlocked pages patches-- e.g., by "mlock -r make -j<N*nr_cpus> all". This did shake out a few races and vmstat accounting bugs, but NOT something I'd recommend as general practice--for kernel builds, that is.

----

Define MCL_INHERIT, MCL_RECURSIVE in <asm-*/mman.h>.
+ x86 and ia64 versions included.
+ other arch can/will be created, if this patch deemed merge-worthy.

Similarly, I'll provide kernel man page update if/when needed.

Example "lock prefix command" in Documentation/vm/mlock.c

 Documentation/vm/mlock.c     |  149 +++++++++++++++++++++++++++++++++++++++++++
 arch/ia64/include/asm/mman.h |    2 
 arch/x86/include/asm/mman.h  |    3 
 fs/binfmt_elf.c              |    9 ++
 include/linux/mm_types.h     |    2 
 kernel/fork.c                |   15 +++-
 mm/mlock.c                   |   19 ++++-
 7 files changed, 191 insertions(+), 8 deletions(-)
arch/ia64/include/asm/mman.h +2 -0
Index: linux-2.6.28-rc7-mmotm-081203/arch/ia64/include/asm/mman.h
===================================================================
@@ -21,6 +21,8 @@
 
 #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 */
+#define MCL_RECURSIVE	8		/* inherit '_FUTURE recursively */
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
mm/mlock.c +14 -5
Index: linux-2.6.28-rc7-mmotm-081203/mm/mlock.c
===================================================================
@@ -573,15 +573,18 @@ asmlinkage long sys_munlock(unsigned lon
 static int do_mlockall(int flags)
 {
 	struct vm_area_struct * vma, * prev = NULL;
+	struct mm_struct *mm = current->mm;
 	unsigned int def_flags = 0;
 
 	if (flags & MCL_FUTURE)
-		def_flags = VM_LOCKED;
-	current->mm->def_flags = def_flags;
-	if (flags == MCL_FUTURE)
+		def_flags = VM_LOCKED;;
+	mm->def_flags = def_flags;
+	if (flags & MCL_INHERIT)
+		mm->mcl_inherit = flags & (MCL_INHERIT | MCL_RECURSIVE);
+	if ((flags & ~(MCL_INHERIT | MCL_RECURSIVE)) == MCL_FUTURE)
 		goto out;
 
-	for (vma = current->mm->mmap; vma ; vma = prev->vm_next) {
+	for (vma = mm->mmap; vma ; vma = prev->vm_next) {
 		unsigned int newflags;
 
 		newflags = vma->vm_flags | VM_LOCKED;
@@ -600,9 +603,15 @@ asmlinkage long sys_mlockall(int flags)
 	unsigned long lock_limit;
 	int ret = -EINVAL;
 
-	if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
+	if (!(flags & (MCL_CURRENT | MCL_FUTURE)))
 		goto out;
 
+	if (flags & ~(MCL_CURRENT | MCL_FUTURE | MCL_INHERIT | MCL_RECURSIVE))
+		goto out;	/* undefined flag bits */
+
+	if ((flags & (MCL_INHERIT | MCL_RECURSIVE)) == MCL_RECURSIVE)
+		goto out;	/* 'RECURSIVE undefined without 'INHERIT */
+
 	ret = -EPERM;
 	if (!can_do_mlock())
 		goto out;
kernel/fork.c +12 -3
Index: linux-2.6.28-rc7-mmotm-081203/kernel/fork.c
===================================================================
@@ -278,7 +278,8 @@ static int dup_mmap(struct mm_struct *mm
 	 */
 	down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING);
 
-	mm->locked_vm = 0;
+	if (!mm->mcl_inherit)
+		mm->locked_vm = 0;
 	mm->mmap = NULL;
 	mm->mmap_cache = NULL;
 	mm->free_area_cache = oldmm->mmap_base;
@@ -316,7 +317,8 @@ static int dup_mmap(struct mm_struct *mm
 		if (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);
@@ -406,6 +408,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLO
 
 static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
 {
+	unsigned long def_flags = 0;
+
 	atomic_set(&mm->mm_users, 1);
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);
@@ -422,9 +426,14 @@ static struct mm_struct * mm_init(struct
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->cached_hole_size = ~0UL;
 	mm_init_owner(mm, p);
+	if (current->mm && current->mm->mcl_inherit) {
+		def_flags = current->mm->def_flags & VM_LOCKED;
+		if (mm->mcl_inherit & MCL_RECURSIVE)
+			mm->mcl_inherit  = current->mm->mcl_inherit;
+	}
 
 	if (likely(!mm_alloc_pgd(mm))) {
-		mm->def_flags = 0;
+		mm->def_flags = def_flags;
 		mmu_notifier_mm_init(mm);
 		return mm;
 	}
fs/binfmt_elf.c +9 -0
Index: linux-2.6.28-rc7-mmotm-081203/fs/binfmt_elf.c
===================================================================
@@ -585,6 +585,7 @@ static int load_elf_binary(struct linux_
 	unsigned long reloc_func_desc = 0;
 	int executable_stack = EXSTACK_DEFAULT;
 	unsigned long def_flags = 0;
+	int mcl_inherit = 0;
 	struct {
 		struct elfhdr elf_ex;
 		struct elfhdr interp_elf_ex;
@@ -749,6 +750,13 @@ static int load_elf_binary(struct linux_
 		SET_PERSONALITY(loc->elf_ex);
 	}
 
+	/* Optionally inherit MCL_FUTURE state before destroying old mm */
+	if (current->mm && current->mm->mcl_inherit) {
+		def_flags = current->mm->def_flags & VM_LOCKED;
+		if (current->mm->mcl_inherit & MCL_RECURSIVE)
+			mcl_inherit  = current->mm->mcl_inherit;
+	}
+
 	/* Flush all traces of the currently running executable */
 	retval = flush_old_exec(bprm);
 	if (retval)
@@ -757,6 +765,7 @@ static int load_elf_binary(struct linux_
 	/* OK, This is the point of no return */
 	current->flags &= ~PF_FORKNOEXEC;
 	current->mm->def_flags = def_flags;
+	current->mm->mcl_inherit = mcl_inherit;
 
 	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
 	   may depend on the personality.  */
arch/x86/include/asm/mman.h +3 -0
Index: linux-2.6.28-rc7-mmotm-081203/arch/x86/include/asm/mman.h
===================================================================
@@ -16,5 +16,8 @@
 
 #define MCL_CURRENT	1		/* lock all current mappings */
 #define MCL_FUTURE	2		/* lock all future mappings */
+#define MCL_INHERIT	4		/* inherit mlocks across fork */
+					/* inherit '_FUTURE flag across fork/exec */
+#define MCL_RECURSIVE	8		/* inherit mlocks recursively */
 
 #endif /* _ASM_X86_MMAN_H */
include/linux/mm_types.h +2 -0
Index: linux-2.6.28-rc7-mmotm-081203/include/linux/mm_types.h
===================================================================
@@ -235,6 +235,8 @@ struct mm_struct {
 	unsigned int token_priority;
 	unsigned int last_interval;
 
+	int mcl_inherit;		/* inherit current/future locks */
+
 	unsigned long flags; /* Must use atomic bitops to access the bits */
 
 	struct core_state *core_state; /* coredumping support */
Documentation/vm/mlock.c new file +149 -0

149 lines not on this page · raw message

--
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>

Reviewed-by on v1 1/1
#5 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

Quoted 7 lines
mm/mlock.c +1 -1
@@ -600,9 +603,15 @@ asmlinkage long sys_mlockall(int flags)
 	unsigned long lock_limit;
 	int ret = -EINVAL;
 
-	if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
+	if (!(flags & (MCL_CURRENT | MCL_FUTURE)))
 		goto out;

mm/mlock.c asmlinkage long sys_mlockall(int flags) · line 617

Quoted 10 lines
mm/mlock.c +6 -0
 
+	if (flags & ~(MCL_CURRENT | MCL_FUTURE | MCL_INHERIT | MCL_RECURSIVE))
+		goto out;	/* undefined flag bits */
+
+	if ((flags & (MCL_INHERIT | MCL_RECURSIVE)) == MCL_RECURSIVE)
+		goto out;	/* 'RECURSIVE undefined without 'INHERIT */
+
 	ret = -EPERM;
 	if (!can_do_mlock())
 		goto out;

looks good to me.

--
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>

maintainer
#6 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

In reply to Lee Schermerhorn

(cc linux-abi. Again.)

Quoted 63 lines · On Wed, 03 Dec 2008 14:04:29 -0500 Lee Schermerhorn <[email protected]>…

Against; 2.6.28-rc7-mmotm-081203

V02: rework vetting of flags argument as suggested by
Kosaki Motohiro.
enhance description as requested by Andrew Morton.

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):

MCL_CURRENT[|MCL_FUTURE]|MCL_INHERIT - inherit memory locks
[vmas' VM_LOCKED flags] across fork(), and inherit MCL_FUTURE behavior [mm's def_flags] across fork() and exec(). Behaves as if child and/or new task called mlockall(MCL_CURRENT|MCL_FUTURE) as first instruction.

MCL_RECURSIVE - inherit MCL_CURRENT|MCL_FUTURE|MCL_INHERIT
[vmas' VM_LOCKED flags for fork() and mm's def_flags and mcl_inherit across fork() and exec()] for all future generations of calling process's descendants. Behaves as if child and/or new task called mlockall(MCL_CURRENT|MCL_FUTURE|MCL_INHERIT|MCL_RECURSIVE) as the first instruction.

In support of a "lock prefix command"--e.g., mlock <cmd> <args> ... Analogous to taskset(1) for cpu affinity or numactl(8) for numa memory policy.

Together with patches to keep mlocked pages off the LRU, this will allow users/admins to lock down applications without modifying them, if their RLIMIT_MEMLOCK is sufficiently large, keeping their pages off the LRU and out of consideration for reclaim.

Potentially useful, as well, in real-time environments to force prefaulting and residency for applications that don't mlock themselves.

Jeff Sharkey at Montana State developed a similar patch for Linux [link no longer accessible], but apparently he never submitted the patch.

I submitted an earlier version of this patch around a year ago. I resurrected it to test the unevictable lru/mlocked pages patches-- e.g., by "mlock -r make -j<N*nr_cpus> all". This did shake out a few races and vmstat accounting bugs, but NOT something I'd recommend as general practice--for kernel builds, that is.

----

Define MCL_INHERIT, MCL_RECURSIVE in <asm-*/mman.h>.
+ x86 and ia64 versions included.
+ other arch can/will be created, if this patch deemed merge-worthy.

Similarly, I'll provide kernel man page update if/when needed.

Example "lock prefix command" in Documentation/vm/mlock.c

...

mm/mlock.c +0 -0
@@ -573,15 +573,18 @@ asmlinkage long sys_munlock(unsigned lon
 static int do_mlockall(int flags)

mm/mlock.c asmlinkage long sys_munlock(unsigned lon · line 580

Quoted 10 lines
mm/mlock.c +2 -3
 {
 	struct vm_area_struct * vma, * prev = NULL;
+	struct mm_struct *mm = current->mm;
 	unsigned int def_flags = 0;
 
 	if (flags & MCL_FUTURE)
-		def_flags = VM_LOCKED;
-	current->mm->def_flags = def_flags;
-	if (flags == MCL_FUTURE)
+		def_flags = VM_LOCKED;;

You get paid by the semicolon?

mm/mlock.c asmlinkage long sys_munlock(unsigned lon · line 583

Quoted 3 lines
mm/mlock.c +3 -0
+	mm->def_flags = def_flags;
+	if (flags & MCL_INHERIT)
+		mm->mcl_inherit = flags & (MCL_INHERIT | MCL_RECURSIVE);

aaaaaaarrrrrrggggggghhhhhhh!

So mm->mcl_inherit is _not_ a boolean meaning "this mm has MCL_INHERIT set", as I naively believed when I saw it. Is it in fact a composite of both MCL_INHERIT and MCL_RECURSIVE, given a badly misleading name and a waffly comment.

Can we please make this clearer?

Quoted 35 lines

...

kernel/fork.c +6 -2
@@ -278,7 +278,8 @@ static int dup_mmap(struct mm_struct *mm
 	 */
 	down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING);
 
-	mm->locked_vm = 0;
+	if (!mm->mcl_inherit)
+		mm->locked_vm = 0;
 	mm->mmap = NULL;
 	mm->mmap_cache = NULL;
 	mm->free_area_cache = oldmm->mmap_base;
@@ -316,7 +317,8 @@ static int dup_mmap(struct mm_struct *mm
 		if (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);
@@ -406,6 +408,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLO
 
 static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
 {
+	unsigned long def_flags = 0;
+
 	atomic_set(&mm->mm_users, 1);
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);

kernel/fork.c static struct mm_struct * mm_init(struct · line 433

Quoted 8 lines
kernel/fork.c +5 -0
@@ -422,9 +426,14 @@ static struct mm_struct * mm_init(struct
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->cached_hole_size = ~0UL;
 	mm_init_owner(mm, p);
+	if (current->mm && current->mm->mcl_inherit) {
+		def_flags = current->mm->def_flags & VM_LOCKED;
+		if (mm->mcl_inherit & MCL_RECURSIVE)
+			mm->mcl_inherit  = current->mm->mcl_inherit;
+	}

hm. That code looks familiar. Not worth a helper function?

Quoted 19 lines
kernel/fork.c +1 -1
 	if (likely(!mm_alloc_pgd(mm))) {
-		mm->def_flags = 0;
+		mm->def_flags = def_flags;
 		mmu_notifier_mm_init(mm);
 		return mm;
 	}

Index: linux-2.6.28-rc7-mmotm-081203/fs/binfmt_elf.c
===================================================================

fs/binfmt_elf.c +1 -0
@@ -585,6 +585,7 @@ static int load_elf_binary(struct linux_
 	unsigned long reloc_func_desc = 0;
 	int executable_stack = EXSTACK_DEFAULT;
 	unsigned long def_flags = 0;
+	int mcl_inherit = 0;
 	struct {
 		struct elfhdr elf_ex;
 		struct elfhdr interp_elf_ex;

fs/binfmt_elf.c static int load_elf_binary(struct linux_ · line 754

Quoted 5 lines
fs/binfmt_elf.c +2 -0
@@ -749,6 +750,13 @@ static int load_elf_binary(struct linux_
 		SET_PERSONALITY(loc->elf_ex);
 	}
 
+	/* Optionally inherit MCL_FUTURE state before destroying old mm */
+	if (current->mm && current->mm->mcl_inherit) {

umm, OK, it looks like current->mm can be null here.

fs/binfmt_elf.c static int load_elf_binary(struct linux_ · line 755

Quoted 1 line
fs/binfmt_elf.c +1 -0
+		def_flags = current->mm->def_flags & VM_LOCKED;

ooh, we finally used local variable def_flags for something. That's been wasting space since 2.2.26 (or earlier).

Quoted 8 lines
fs/binfmt_elf.c +4 -0
+		if (current->mm->mcl_inherit & MCL_RECURSIVE)
+			mcl_inherit  = current->mm->mcl_inherit;
+	}
+
 	/* Flush all traces of the currently running executable */
 	retval = flush_old_exec(bprm);
 	if (retval)

fs/binfmt_elf.c static int load_elf_binary(struct linux_ · line 771

Quoted 7 lines
fs/binfmt_elf.c +1 -0
@@ -757,6 +765,7 @@ static int load_elf_binary(struct linux_
 	/* OK, This is the point of no return */
 	current->flags &= ~PF_FORKNOEXEC;
 	current->mm->def_flags = def_flags;
+	current->mm->mcl_inherit = mcl_inherit;
 
 	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
 	   may depend on the personality.  */

Why is this done in binfmt_elf.c? Doesn't this preclude the operation of these new flags for other binary formats?

Quoted 18 lines

Index: linux-2.6.28-rc7-mmotm-081203/arch/x86/include/asm/mman.h
===================================================================

arch/x86/include/asm/mman.h +3 -0
@@ -16,5 +16,8 @@
 
 #define MCL_CURRENT	1		/* lock all current mappings */
 #define MCL_FUTURE	2		/* lock all future mappings */
+#define MCL_INHERIT	4		/* inherit mlocks across fork */
+					/* inherit '_FUTURE flag across fork/exec */
+#define MCL_RECURSIVE	8		/* inherit mlocks recursively */
 
 #endif /* _ASM_X86_MMAN_H */

Index: linux-2.6.28-rc7-mmotm-081203/include/linux/mm_types.h
===================================================================

include/linux/mm_types.h struct mm_struct { · line 240

Quoted 6 lines
include/linux/mm_types.h +2 -0
@@ -235,6 +235,8 @@ struct mm_struct {
 	unsigned int token_priority;
 	unsigned int last_interval;
 
+	int mcl_inherit;		/* inherit current/future locks */
+
 	unsigned long flags; /* Must use atomic bitops to access the bits */

I was thinking that the boolean mcl_inherit could become a bit in mm.flags. That was before I unmisled myself about it.

Perhaps we could use two bits. That might get a bit nasty.

--
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>

#7 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

Quoted 1 line · Andrew Morton

(cc linux-abi. Again.)

Sorry.

Quoted 71 lines · On Wed, 03 Dec 2008 14:04:29 -0500 Lee Schermerhorn <[email protected]>…
Quoted 69 lines

Against; 2.6.28-rc7-mmotm-081203

V02: rework vetting of flags argument as suggested by
Kosaki Motohiro.
enhance description as requested by Andrew Morton.

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):

MCL_CURRENT[|MCL_FUTURE]|MCL_INHERIT - inherit memory locks
[vmas' VM_LOCKED flags] across fork(), and inherit MCL_FUTURE behavior [mm's def_flags] across fork() and exec(). Behaves as if child and/or new task called mlockall(MCL_CURRENT|MCL_FUTURE) as first instruction.

MCL_RECURSIVE - inherit MCL_CURRENT|MCL_FUTURE|MCL_INHERIT
[vmas' VM_LOCKED flags for fork() and mm's def_flags and mcl_inherit across fork() and exec()] for all future generations of calling process's descendants. Behaves as if child and/or new task called mlockall(MCL_CURRENT|MCL_FUTURE|MCL_INHERIT|MCL_RECURSIVE) as the first instruction.

In support of a "lock prefix command"--e.g., mlock <cmd> <args> ... Analogous to taskset(1) for cpu affinity or numactl(8) for numa memory policy.

Together with patches to keep mlocked pages off the LRU, this will allow users/admins to lock down applications without modifying them, if their RLIMIT_MEMLOCK is sufficiently large, keeping their pages off the LRU and out of consideration for reclaim.

Potentially useful, as well, in real-time environments to force prefaulting and residency for applications that don't mlock themselves.

Jeff Sharkey at Montana State developed a similar patch for Linux [link no longer accessible], but apparently he never submitted the patch.

I submitted an earlier version of this patch around a year ago. I resurrected it to test the unevictable lru/mlocked pages patches-- e.g., by "mlock -r make -j<N*nr_cpus> all". This did shake out a few races and vmstat accounting bugs, but NOT something I'd recommend as general practice--for kernel builds, that is.

----

Define MCL_INHERIT, MCL_RECURSIVE in <asm-*/mman.h>.
+ x86 and ia64 versions included.
+ other arch can/will be created, if this patch deemed merge-worthy.

Similarly, I'll provide kernel man page update if/when needed.

Example "lock prefix command" in Documentation/vm/mlock.c

...

mm/mlock.c +1 -0
@@ -573,15 +573,18 @@ asmlinkage long sys_munlock(unsigned lon
 static int do_mlockall(int flags)
 {
 	struct vm_area_struct * vma, * prev = NULL;
+	struct mm_struct *mm = current->mm;
 	unsigned int def_flags = 0;
 
Quoted 7 lines

mm/mlock.c asmlinkage long sys_munlock(unsigned lon · line 580

Quoted 5 lines
mm/mlock.c +1 -3
 	if (flags & MCL_FUTURE)
-		def_flags = VM_LOCKED;
-	current->mm->def_flags = def_flags;
-	if (flags == MCL_FUTURE)
+		def_flags = VM_LOCKED;;

You get paid by the semicolon?

Nope. Interestingly, ckeckpatch was fine with this. [It did warn about

Quoted 1 line

80 char line in x86 mman.h, but there was already a much longer line,

so I left it. Fixed now so that patch is squeaky clean, as far as checkpatch is concerned.]

Quoted 7 lines

mm/mlock.c asmlinkage long sys_munlock(unsigned lon · line 583

Quoted 4 lines
mm/mlock.c +3 -0
+	mm->def_flags = def_flags;
+	if (flags & MCL_INHERIT)
+		mm->mcl_inherit = flags & (MCL_INHERIT | MCL_RECURSIVE);

aaaaaaarrrrrrggggggghhhhhhh!

Quoted 6 lines

So mm->mcl_inherit is _not_ a boolean meaning "this mm has MCL_INHERIT set", as I naively believed when I saw it. Is it in fact a composite of both MCL_INHERIT and MCL_RECURSIVE, given a badly misleading name and a waffly comment.

Can we please make this clearer?

How about "mcl_inherit_mlocks_possibly_recursively" ?

Seriously, it made/makes sense to me. If mcl_inherit is non-zero, it WILL contain MCL_INHERIT, meaning that existing mlocks and any VM_LOCKED in def_flags will be inherited across the next fork or exec [of course, existing mlocks can't be inherited across exec as we discard the address space]. It may also contain MCL_RECURSIVE--tested separately--meaning that the contents of mcl_inherit, itself, will also be inherited across the next and future forks/execs, until/unless a descendant invokes mlockall() w/o MCL_INHERIT or MCL_RECURSIVE to clear out mcl_inherit.

This seemed a bit much to try to explain on line where mcl_inherit is declared in mm_types. More appropriate to a man page, I would have
thought. How about a Documentation/vm doc?

Meanwhile, perhaps: "mcl_inherit" -> "mcl_inherit_flags" or "mcl_flags" or "mlock_flags", or such?

Quoted 38 lines
Quoted 38 lines

...

kernel/fork.c +6 -2
@@ -278,7 +278,8 @@ static int dup_mmap(struct mm_struct *mm
 	 */
 	down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING);
 
-	mm->locked_vm = 0;
+	if (!mm->mcl_inherit)
+		mm->locked_vm = 0;
 	mm->mmap = NULL;
 	mm->mmap_cache = NULL;
 	mm->free_area_cache = oldmm->mmap_base;
@@ -316,7 +317,8 @@ static int dup_mmap(struct mm_struct *mm
 		if (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);
@@ -406,6 +408,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLO
 
 static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
 {
+	unsigned long def_flags = 0;
+
 	atomic_set(&mm->mm_users, 1);
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);
@@ -422,9 +426,14 @@ static struct mm_struct * mm_init(struct
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->cached_hole_size = ~0UL;
Quoted 8 lines

kernel/fork.c static struct mm_struct * mm_init(struct · line 433

Quoted 6 lines
kernel/fork.c +5 -0
 	mm_init_owner(mm, p);
+	if (current->mm && current->mm->mcl_inherit) {
+		def_flags = current->mm->def_flags & VM_LOCKED;
+		if (mm->mcl_inherit & MCL_RECURSIVE)
+			mm->mcl_inherit  = current->mm->mcl_inherit;
+	}

hm. That code looks familiar. Not worth a helper function?

If we could remove the copy in load_elf_binary(), point would be moot.

More below.

Quoted 23 lines
Quoted 23 lines
kernel/fork.c +1 -1
 	if (likely(!mm_alloc_pgd(mm))) {
-		mm->def_flags = 0;
+		mm->def_flags = def_flags;
 		mmu_notifier_mm_init(mm);
 		return mm;
 	}

Index: linux-2.6.28-rc7-mmotm-081203/fs/binfmt_elf.c
===================================================================

fs/binfmt_elf.c +1 -0
@@ -585,6 +585,7 @@ static int load_elf_binary(struct linux_
 	unsigned long reloc_func_desc = 0;
 	int executable_stack = EXSTACK_DEFAULT;
 	unsigned long def_flags = 0;
+	int mcl_inherit = 0;
 	struct {
 		struct elfhdr elf_ex;
 		struct elfhdr interp_elf_ex;
@@ -749,6 +750,13 @@ static int load_elf_binary(struct linux_
 		SET_PERSONALITY(loc->elf_ex);
 	}
 
Quoted 4 lines

fs/binfmt_elf.c static int load_elf_binary(struct linux_ · line 754

Quoted 2 lines
fs/binfmt_elf.c +2 -0
+	/* Optionally inherit MCL_FUTURE state before destroying old mm */
+	if (current->mm && current->mm->mcl_inherit) {

umm, OK, it looks like current->mm can be null here.

Probably not here. IIRC, it can be NULL [for init] up in mm_init() and I probably just cut and pasted, instead of a helper function...

Quoted 5 lines

fs/binfmt_elf.c static int load_elf_binary(struct linux_ · line 755

Quoted 2 lines
fs/binfmt_elf.c +1 -0
+		def_flags = current->mm->def_flags & VM_LOCKED;

ooh, we finally used local variable def_flags for something. That's been wasting space since 2.2.26 (or earlier).

def_flags was being used to clear out the current->mm->def_flags. Don't know why, tho'. See below...

Quoted 14 lines
Quoted 14 lines
fs/binfmt_elf.c +5 -0
+		if (current->mm->mcl_inherit & MCL_RECURSIVE)
+			mcl_inherit  = current->mm->mcl_inherit;
+	}
+
 	/* Flush all traces of the currently running executable */
 	retval = flush_old_exec(bprm);
 	if (retval)
@@ -757,6 +765,7 @@ static int load_elf_binary(struct linux_
 	/* OK, This is the point of no return */
 	current->flags &= ~PF_FORKNOEXEC;
 	current->mm->def_flags = def_flags;
+	current->mm->mcl_inherit = mcl_inherit;
 
Quoted 5 lines

fs/binfmt_elf.c static int load_elf_binary(struct linux_ · line 771

Quoted 2 lines
fs/binfmt_elf.c +0 -0
 	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
 	   may depend on the personality.  */

Why is this done in binfmt_elf.c? Doesn't this preclude the operation of these new flags for other binary formats?

Because binfmt_elf.c is the only binary format loader [that I can see] that takes it upon itself to reinitialize mm->def_flags, which has already been set up in mm_init(). I wondered, myself, why this is the case, but I didn't dare just remove it, lest it reintroduce some obscure bug. So, I duplicated my version of def_flags [and mcl_inherit] initialization here.

Now that you've raised the question: why, indeed, does the elf format loader reinit def_flags? Can we just remove this?

Quoted 22 lines
Quoted 22 lines

Index: linux-2.6.28-rc7-mmotm-081203/arch/x86/include/asm/mman.h
===================================================================

arch/x86/include/asm/mman.h +3 -0
@@ -16,5 +16,8 @@
 
 #define MCL_CURRENT	1		/* lock all current mappings */
 #define MCL_FUTURE	2		/* lock all future mappings */
+#define MCL_INHERIT	4		/* inherit mlocks across fork */
+					/* inherit '_FUTURE flag across fork/exec */
+#define MCL_RECURSIVE	8		/* inherit mlocks recursively */
 
 #endif /* _ASM_X86_MMAN_H */

Index: linux-2.6.28-rc7-mmotm-081203/include/linux/mm_types.h
===================================================================

include/linux/mm_types.h +0 -0
@@ -235,6 +235,8 @@ struct mm_struct {
 	unsigned int token_priority;
 	unsigned int last_interval;
 
Quoted 8 lines

include/linux/mm_types.h struct mm_struct { · line 240

Quoted 3 lines
include/linux/mm_types.h +2 -0
+	int mcl_inherit;		/* inherit current/future locks */
+
 	unsigned long flags; /* Must use atomic bitops to access the bits */

I was thinking that the boolean mcl_inherit could become a bit in mm.flags. That was before I unmisled myself about it.

Perhaps we could use two bits. That might get a bit nasty.

I did look for someplace to add these flags, before deciding on a new member. The "Must use atomic bitops", and the fact that mm->flags seems used soley for controlling core dumping [and defined in sched.h, no less!], put me off from going that route. Similarly, because def_flags is an initializer for the vma's vm_flags, I didn't want to pollute that. I figured the 'int' would fill a padding slot on 64-bit archs, but does add to mm size for 32-bit archs.

Suggestions?
I'll hold off on a re-spin, pending resolution of some of these issues.

Thanks for the thorough review.

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>

#8 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

In reply to Andrew Morton

Sorry for the resend. I had the 'linux-api' address wrong on my reponse to Andrew. Want to include the api list in this exchange.

Quoted 72 lines · Andrew Morton

(cc linux-abi. Again.)

Quoted 68 lines · On Wed, 03 Dec 2008 14:04:29 -0500 Lee Schermerhorn…

Against; 2.6.28-rc7-mmotm-081203

V02: rework vetting of flags argument as suggested by
Kosaki Motohiro.
enhance description as requested by Andrew Morton.

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):

MCL_CURRENT[|MCL_FUTURE]|MCL_INHERIT - inherit memory locks
[vmas' VM_LOCKED flags] across fork(), and inherit MCL_FUTURE behavior [mm's def_flags] across fork() and exec(). Behaves as if child and/or new task called mlockall(MCL_CURRENT|MCL_FUTURE) as first instruction.

MCL_RECURSIVE - inherit MCL_CURRENT|MCL_FUTURE|MCL_INHERIT
[vmas' VM_LOCKED flags for fork() and mm's def_flags and mcl_inherit across fork() and exec()] for all future generations of calling process's descendants. Behaves as if child and/or new task called mlockall(MCL_CURRENT|MCL_FUTURE|MCL_INHERIT|MCL_RECURSIVE) as the first instruction.

In support of a "lock prefix command"--e.g., mlock <cmd> <args> ... Analogous to taskset(1) for cpu affinity or numactl(8) for numa memory policy.

Together with patches to keep mlocked pages off the LRU, this will allow users/admins to lock down applications without modifying them, if their RLIMIT_MEMLOCK is sufficiently large, keeping their pages off the LRU and out of consideration for reclaim.

Potentially useful, as well, in real-time environments to force prefaulting and residency for applications that don't mlock themselves.

Jeff Sharkey at Montana State developed a similar patch for Linux [link no longer accessible], but apparently he never submitted the patch.

I submitted an earlier version of this patch around a year ago. I resurrected it to test the unevictable lru/mlocked pages patches-- e.g., by "mlock -r make -j<N*nr_cpus> all". This did shake out a few races and vmstat accounting bugs, but NOT something I'd recommend as general practice--for kernel builds, that is.

----

Define MCL_INHERIT, MCL_RECURSIVE in <asm-*/mman.h>.
+ x86 and ia64 versions included.
+ other arch can/will be created, if this patch deemed merge-worthy.

Similarly, I'll provide kernel man page update if/when needed.

Example "lock prefix command" in Documentation/vm/mlock.c

...

mm/mlock.c +1 -0
@@ -573,15 +573,18 @@ asmlinkage long sys_munlock(unsigned lon
 static int do_mlockall(int flags)
 {
 	struct vm_area_struct * vma, * prev = NULL;
+	struct mm_struct *mm = current->mm;
 	unsigned int def_flags = 0;
 
Quoted 7 lines

mm/mlock.c asmlinkage long sys_munlock(unsigned lon · line 580

Quoted 5 lines
mm/mlock.c +1 -3
 	if (flags & MCL_FUTURE)
-		def_flags = VM_LOCKED;
-	current->mm->def_flags = def_flags;
-	if (flags == MCL_FUTURE)
+		def_flags = VM_LOCKED;;

You get paid by the semicolon?

Nope. Interestingly, ckeckpatch was fine with this. [It did warn about

Quoted 1 line

80 char line in x86 mman.h, but there was already a much longer line,

so I left it. Fixed now so that patch is squeaky clean, as far as checkpatch is concerned.]

Quoted 7 lines

mm/mlock.c asmlinkage long sys_munlock(unsigned lon · line 583

Quoted 4 lines
mm/mlock.c +3 -0
+	mm->def_flags = def_flags;
+	if (flags & MCL_INHERIT)
+		mm->mcl_inherit = flags & (MCL_INHERIT | MCL_RECURSIVE);

aaaaaaarrrrrrggggggghhhhhhh!

Quoted 6 lines

So mm->mcl_inherit is _not_ a boolean meaning "this mm has MCL_INHERIT set", as I naively believed when I saw it. Is it in fact a composite of both MCL_INHERIT and MCL_RECURSIVE, given a badly misleading name and a waffly comment.

Can we please make this clearer?

How about "mcl_inherit_mlocks_possibly_recursively" ?

Seriously, it made/makes sense to me. If mcl_inherit is non-zero, it WILL contain MCL_INHERIT, meaning that existing mlocks and any VM_LOCKED in def_flags will be inherited across the next fork or exec [def_flags only]. It may also contain MCL_RECURSIVE--tested separately--meaning that the contents of mcl_inherit, itself, will also be inherited across the next and future forks/execs, until/unless a descendant invokes mlockall() w/o MCL_INHERIT or MCL_RECURSIVE to clear out mcl_inherit.

This seemed a bit much to try to explain on line where mcl_inherit is declared in mm_types. More appropriate to a man page, I would have
thought. How about a Documentation/vm doc?

Meanwhile, perhaps: "mcl_inherit" -> "mcl_inherit_flags" or "mcl_flags" or "mlock_flags", or such?

Quoted 38 lines
Quoted 38 lines

...

kernel/fork.c +6 -2
@@ -278,7 +278,8 @@ static int dup_mmap(struct mm_struct *mm
 	 */
 	down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING);
 
-	mm->locked_vm = 0;
+	if (!mm->mcl_inherit)
+		mm->locked_vm = 0;
 	mm->mmap = NULL;
 	mm->mmap_cache = NULL;
 	mm->free_area_cache = oldmm->mmap_base;
@@ -316,7 +317,8 @@ static int dup_mmap(struct mm_struct *mm
 		if (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);
@@ -406,6 +408,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLO
 
 static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
 {
+	unsigned long def_flags = 0;
+
 	atomic_set(&mm->mm_users, 1);
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);
@@ -422,9 +426,14 @@ static struct mm_struct * mm_init(struct
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->cached_hole_size = ~0UL;
Quoted 8 lines

kernel/fork.c static struct mm_struct * mm_init(struct · line 433

Quoted 6 lines
kernel/fork.c +5 -0
 	mm_init_owner(mm, p);
+	if (current->mm && current->mm->mcl_inherit) {
+		def_flags = current->mm->def_flags & VM_LOCKED;
+		if (mm->mcl_inherit & MCL_RECURSIVE)
+			mm->mcl_inherit  = current->mm->mcl_inherit;
+	}

hm. That code looks familiar. Not worth a helper function?

If we could remove the copy in load_elf_binary(), point would be moot.

More below.

Quoted 23 lines
Quoted 23 lines
kernel/fork.c +1 -1
 	if (likely(!mm_alloc_pgd(mm))) {
-		mm->def_flags = 0;
+		mm->def_flags = def_flags;
 		mmu_notifier_mm_init(mm);
 		return mm;
 	}

Index: linux-2.6.28-rc7-mmotm-081203/fs/binfmt_elf.c
===================================================================

fs/binfmt_elf.c +1 -0
@@ -585,6 +585,7 @@ static int load_elf_binary(struct linux_
 	unsigned long reloc_func_desc = 0;
 	int executable_stack = EXSTACK_DEFAULT;
 	unsigned long def_flags = 0;
+	int mcl_inherit = 0;
 	struct {
 		struct elfhdr elf_ex;
 		struct elfhdr interp_elf_ex;
@@ -749,6 +750,13 @@ static int load_elf_binary(struct linux_
 		SET_PERSONALITY(loc->elf_ex);
 	}
 
Quoted 4 lines

fs/binfmt_elf.c static int load_elf_binary(struct linux_ · line 754

Quoted 2 lines
fs/binfmt_elf.c +2 -0
+	/* Optionally inherit MCL_FUTURE state before destroying old mm */
+	if (current->mm && current->mm->mcl_inherit) {

umm, OK, it looks like current->mm can be null here.

Probably not here. IIRC, it can be NULL [for init] up in mm_init() and I probably just cut and pasted, instead of a helper function...

Quoted 5 lines

fs/binfmt_elf.c static int load_elf_binary(struct linux_ · line 755

Quoted 2 lines
fs/binfmt_elf.c +1 -0
+		def_flags = current->mm->def_flags & VM_LOCKED;

ooh, we finally used local variable def_flags for something. That's been wasting space since 2.2.26 (or earlier).

def_flags was being used to clear out the current->mm->def_flags. Don't know why, tho'. See below...

Quoted 14 lines
Quoted 14 lines
fs/binfmt_elf.c +5 -0
+		if (current->mm->mcl_inherit & MCL_RECURSIVE)
+			mcl_inherit  = current->mm->mcl_inherit;
+	}
+
 	/* Flush all traces of the currently running executable */
 	retval = flush_old_exec(bprm);
 	if (retval)
@@ -757,6 +765,7 @@ static int load_elf_binary(struct linux_
 	/* OK, This is the point of no return */
 	current->flags &= ~PF_FORKNOEXEC;
 	current->mm->def_flags = def_flags;
+	current->mm->mcl_inherit = mcl_inherit;
 
Quoted 5 lines

fs/binfmt_elf.c static int load_elf_binary(struct linux_ · line 771

Quoted 2 lines
fs/binfmt_elf.c +0 -0
 	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
 	   may depend on the personality.  */

Why is this done in binfmt_elf.c? Doesn't this preclude the operation of these new flags for other binary formats?

Because binfmt_elf.c is the only binary format loader [that I can see] that takes it upon itself to reinitialize mm->def_flags, which has already been set up in mm_init(). I wondered, myself, why this is the case, but I didn't dare just remove it, lest it reintroduce some obscure bug. So, I duplicated my version of def_flags [and mcl_inherit] initialization here.

Now that you've raised the question: why, indeed, does the elf format loader reinit def_flags? Can we just remove this?

Quoted 22 lines
Quoted 22 lines

Index: linux-2.6.28-rc7-mmotm-081203/arch/x86/include/asm/mman.h
===================================================================

arch/x86/include/asm/mman.h +3 -0
@@ -16,5 +16,8 @@
 
 #define MCL_CURRENT	1		/* lock all current mappings */
 #define MCL_FUTURE	2		/* lock all future mappings */
+#define MCL_INHERIT	4		/* inherit mlocks across fork */
+					/* inherit '_FUTURE flag across fork/exec */
+#define MCL_RECURSIVE	8		/* inherit mlocks recursively */
 
 #endif /* _ASM_X86_MMAN_H */

Index: linux-2.6.28-rc7-mmotm-081203/include/linux/mm_types.h
===================================================================

include/linux/mm_types.h +0 -0
@@ -235,6 +235,8 @@ struct mm_struct {
 	unsigned int token_priority;
 	unsigned int last_interval;
 
Quoted 8 lines

include/linux/mm_types.h struct mm_struct { · line 240

Quoted 3 lines
include/linux/mm_types.h +2 -0
+	int mcl_inherit;		/* inherit current/future locks */
+
 	unsigned long flags; /* Must use atomic bitops to access the bits */

I was thinking that the boolean mcl_inherit could become a bit in mm.flags. That was before I unmisled myself about it.

Perhaps we could use two bits. That might get a bit nasty.

I did look for someplace to add these flags, before deciding on a new member. The "Must use atomic bitops", and the fact that mm->flags seems used soley for controlling core dumping [and defined in sched.h, no less!], put me off from going that route. Similarly, because def_flags is an initializer for the vma's vm_flags, I didn't want to pollute that. I figured the 'int' would fill a padding slot on 64-bit archs, but does add to mm size for 32-bit archs.

Suggestions?
I'll hold off on a re-spin, pending resolution of some of these issues.

Thanks for the thorough review.

Lee

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#9 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

Quoted 12 lines · Lee Schermerhorn
Quoted 1 line
Quoted 1 line

In support of a "lock prefix command"--e.g., mlock <cmd>

<args> ...

Quoted 10 lines
Quoted 10 lines

Analogous to taskset(1) for cpu affinity or numactl(8) for numa memory policy.

Together with patches to keep mlocked pages off the LRU, this will allow users/admins to lock down applications without modifying them, if their RLIMIT_MEMLOCK is sufficiently large, keeping their pages off the LRU and out of consideration for reclaim.

Potentially useful, as well, in real-time environments to force prefaulting and residency for applications that don't mlock themselves.

This is a bit scary to me. Privilege and mode inheritance across processes is the root of many nasty surprises, security and otherwise.

Here's a crazy alternative: add a flag to containers instead? I think this is a better match to what you're trying to do and will keep people from being surprised when an mlockall call in one thread causes a fork/exec in another thread to crash their box, but only sometimes.

Signature · 6 lines
Mathematics is the supreme nostalgia of our time.

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#10 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

Quoted 11 lines · Matt Mackall
Quoted 10 lines · Lee Schermerhorn
Quoted 1 line
Quoted 1 line

In support of a "lock prefix command"--e.g., mlock <cmd>

<args> ...

Quoted 8 lines
Quoted 8 lines

Analogous to taskset(1) for cpu affinity or numactl(8) for numa memory policy.

Together with patches to keep mlocked pages off the LRU, this will allow users/admins to lock down applications without modifying them, if their RLIMIT_MEMLOCK is sufficiently large, keeping their pages off the LRU and out of consideration for reclaim.

Quoted 5 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

Potentially useful, as well, in real-time environments to force prefaulting and residency for applications that don't mlock themselves.

This is a bit scary to me. Privilege and mode inheritance across processes is the root of many nasty surprises, security and otherwise.

Hi, Matt:

Could you explain more about this issue? I believe that the patch doesn't provide any privileges or capabilities that a process doesn't already have. It just allows one to cause a process and, optionally, its descendants, to behave as if one had modified the sources to invoke mlockall() directly. It is still subject to each individual task's resource limits. At least, that was my intent.

Quoted 5 lines

Here's a crazy alternative: add a flag to containers instead? I think this is a better match to what you're trying to do and will keep people from being surprised when an mlockall call in one thread causes a fork/exec in another thread to crash their box, but only sometimes.

Not so crazy. It isn't really a better match, IMO [more below], but I can see providing a flag to enable/disable this ability in the container. Initially, the default could be disabled. If/when it's been around long enough that people are comfortable with it, perhaps the default could be flipped to enabled.

As far as "what I'm trying to do": I see this as exactly like using taskset to set the cpu affinity of a task, or numactl to set the task mempolicy without modifying the source. If one had access to the program source and wouldn't, e.g., void a support contract by modifying it, one could just insert the calls into the source itself. These would still be subject to, but "finer grain" than, external administrative controls, such as cpuset allowed mems and cpus.

But, sometimes, it's very convenient to use the prefix commands to effect the same behavior. I could certainly use it in the Oracle, SAP, ... benchmarking that I occasionally help out with. Actually, as I have the patches, I can create custom kernels for the purpose of demonstrating the effects. However, I think it would be useful for customers someday to have this feature in distro kernels.

I don't understand your comment about threads and crashing the box. If an inherited mlockall() can crash Linux, then inserting the call into the source could also crash it. I think that's a bug we'd need to fix in any case. Indeed, using this facility during testing of the unevictable lru/mlocked pages work DID uncover bugs that I might not
have seen otherwise. If you meant "cause OOMs", I agree that this
could happen, as well but, again, I think this would be the same behavior as if the calls were inserted into the source.

Regarding one thread being surprised by what another thread did: if you mean threads within the same executable, I'd expect them to part of the same program. One hopes that someone knows the big picture--what all the threads are doing--obviating any such surprises. But, I recall that you work/ed in the embedded space, and perhaps threads mean something different to you.

Anyway...

This is a pretty small patch that I can maintain out of tree for my own use in testing if people don't think its usefulness outweighs any concerns it raises. Customers won't be able to use it, but thems the breaks.

Regards,
Lee

Quoted 1 line

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#11 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

Quoted 18 lines · Lee Schermerhorn
Quoted 11 lines · Matt Mackall
Quoted 10 lines · Lee Schermerhorn
Quoted 1 line
Quoted 1 line

In support of a "lock prefix command"--e.g., mlock <cmd>

<args> ...

Quoted 8 lines
Quoted 8 lines

Analogous to taskset(1) for cpu affinity or numactl(8) for numa memory policy.

Together with patches to keep mlocked pages off the LRU, this will allow users/admins to lock down applications without modifying them, if their RLIMIT_MEMLOCK is sufficiently large, keeping their pages off the LRU and out of consideration for reclaim.

Quoted 5 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

Potentially useful, as well, in real-time environments to force prefaulting and residency for applications that don't mlock themselves.

This is a bit scary to me. Privilege and mode inheritance across processes is the root of many nasty surprises, security and otherwise.

Quoted 8 lines

Hi, Matt:

Could you explain more about this issue? I believe that the patch doesn't provide any privileges or capabilities that a process doesn't already have. It just allows one to cause a process and, optionally, its descendants, to behave as if one had modified the sources to invoke mlockall() directly. It is still subject to each individual task's resource limits. At least, that was my intent.

Again, it's about inheriting *something* across processes. This historically creates surprises. When the thing being inherited is a privilege, the surprises are security holes. I can't tell you what the surprises are, only that I expect there to be some.

mlockall is not a privilege in itself, but it is a non-standard mode of operation that most processes are not designed for or expecting, and it does relate to the handling of a finite resource with system stability implications. If the thing that turns on this mode is buried inside some poorly written app that decides it needs to mlockall somewhere, the 'surprise' can occur far away - in the child of a child of a thread an hour later. And the surprise can be fatal - all memory eaten up, because our process just happened to run without an rlimit.

I've seen this with RT. An app temporarily elevates itself to RT, and unrelatedly forks another process. The second short-lived process kicks off a daemon that sometime later consumes all CPU in a busy loop (in this case waiting on I/O that never happens because everything else is shut out).

Doing it as a container parameter means that you explicitly recognize that 'everything in the container' gets this mode. And you've probably also given a thought to 'how big is this container' and the like as well.

Quoted 3 lines

As far as "what I'm trying to do": I see this as exactly like using taskset to set the cpu affinity of a task, or numactl to set the task mempolicy without modifying the source.

Oh sure, I completely get that and I think it's a useful notion. And I think the above analogous interfaces have more or less the same issues, except that mlockall is a much older and more widely used API. Containers are a better match here too, but the above predate containers.

Quoted 3 lines

If one had access to the
program source and wouldn't, e.g., void a support contract by modifying it, one could just insert the calls into the source itself.

Huh? We would of course set up a container 'from the outside'. By comparison, your mlockall() call traditionally operates from 'from the inside', and you're proposing to add a flag and a helper program that makes it work 'from the outside' too. Which is a bit hackish.

Signature · 6 lines
Mathematics is the supreme nostalgia of our time.

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#12 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

In reply to Lee Schermerhorn
Quoted 1 line · Lee Schermerhorn

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):

FWIW, I really liked this patch series. And I think there is still value in a generic "mlock" wrapper utility that I can use. Sure, the later on containers suggestions are all wonderful in theory but I don't see that that went anywhere either (and I disagree that we can't trust people to use this right without doing silly things) - if I'm really right that this got dropped on the floor, can we resurrect it in .31 please?

Jon.

--
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>

#13 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

Quoted 10 lines · Lee Schermerhorn
Quoted 2 lines

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):

FWIW, I really liked this patch series. And I think there is still value in a generic "mlock" wrapper utility that I can use. Sure, the later on containers suggestions are all wonderful in theory but I don't see that that went anywhere either (and I disagree that we can't trust people to use this right without doing silly things) - if I'm really right that this got dropped on the floor, can we resurrect it in .31 please?

I guess Lee is really really busy now.
Can you make V3 patch instead?

--
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>

#14 lore raw

Re: [PATCH] - support inheritance of mlocks across fork/exec V2

Quoted 4 lines · KOSAKI Motohiro
Quoted 4 lines · Lee Schermerhorn
Quoted 2 lines

Add support for mlockall(MCL_INHERIT|MCL_RECURSIVE):

Quoted 8 lines
Quoted 6 lines

FWIW, I really liked this patch series. And I think there is still value in a generic "mlock" wrapper utility that I can use. Sure, the later on containers suggestions are all wonderful in theory but I don't see that that went anywhere either (and I disagree that we can't trust people to use this right without doing silly things) - if I'm really right that this got dropped on the floor, can we resurrect it in .31 please?

I guess Lee is really really busy now.

Who isn't? :)

Quoted 1 line

Can you make V3 patch instead?

I'm happy to rebase onto a recent kernel and repost if it's not something that's instantly going to get dropped on the floor. I thought about this patch series a few minutes ago when I found myself recompiling a certain piece of audio software and realized there's no reason I shouldn't just be able to e.g. just do the following:

mlock --all -- pulseaudio --start --high-priority=1

As a test of my sanity in this case, but there are other times when I'm running software on RT kernels and would love to have that as a wrapper to temporarily prevent a performance hit.

Jon.

--
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>

Reviewed-by
#15 lore raw
In reply to Lee Schermerhorn

only one nit.

mm/mlock.c asmlinkage long sys_mlockall(int flags) · line 607

Quoted 8 lines
mm/mlock.c +2 -1
@@ -599,7 +602,8 @@ 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 | MCL_RECURSIVE)))
 		goto out;

from patch description, I think mlockall(MCL_INHERIT) and mlockall(MCL_RECURSIVE) are incorrect. right?

if so, I think following likes error check is needed.

if (!(flags & (MCL_CURRENT | MCL_FUTURE)))

	goto out;

if ((flags & (MCL_INHERIT | MECL_RECURSIVE)) == MCL_RECURSIVE)

	goto out;

otherthings, looks good to me.

--
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>

#16 lore raw
Quoted 14 lines · KOSAKI Motohiro

only one nit.

mm/mlock.c asmlinkage long sys_mlockall(int flags) · line 607

Quoted 8 lines
mm/mlock.c +2 -1
@@ -599,7 +602,8 @@ 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 | MCL_RECURSIVE)))
 		goto out;

from patch description, I think mlockall(MCL_INHERIT) and mlockall(MCL_RECURSIVE) are incorrect. right?

Quoted 8 lines

if so, I think following likes error check is needed.

if (!(flags & (MCL_CURRENT | MCL_FUTURE)))

	goto out;

if ((flags & (MCL_INHERIT | MECL_RECURSIVE)) == MCL_RECURSIVE)

	goto out;

Hello, Kosaki-san:

Thanks for looking at this. I think you mean that:

1) don't allow MCL_INHERIT | MCL_RECURSIVE without either MCL_CURRENT or MCL_FUTURE, and

2) MCL_RECURSIVE without MCL_INHERIT does not make sense, either.

Is this correct?

I guess I agree with you. As is stands, my patch would allow MCL_INHERIT[|MCL_RECURSIVE] to sneak through with neither MCL_CURRENT nor MCL_FUTURE set. Looks like this would result in mlock_fixup() being called with a newflags that does not containing VM_LOCKED. This would
be treated as munlockall(). Not good. Your first check would catch
this.

The second condition would be a no-op, I think. We only look at look for MCL_RECURSIVE in mm->mcl_inherit when mcl_inherit is non-zero; and we only set mcl_inherit when MCL_INHERIT is specified. But, if the caller specified MCL_RECURSIVE, they probably intended something to happen, and since it won't, best to return an error.

I'll fix this up and send it out to the wider distribution that Andrew requested.

Thanks, again.
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>

#17 lore raw

Hi

Quoted 10 lines

Hello, Kosaki-san:

Thanks for looking at this. I think you mean that:

1) don't allow MCL_INHERIT | MCL_RECURSIVE without either MCL_CURRENT or MCL_FUTURE, and

2) MCL_RECURSIVE without MCL_INHERIT does not make sense, either.

Is this correct?

Yup. you describe just my opnion.
thanks.

Quoted 13 lines

I guess I agree with you. As is stands, my patch would allow MCL_INHERIT[|MCL_RECURSIVE] to sneak through with neither MCL_CURRENT nor MCL_FUTURE set. Looks like this would result in mlock_fixup() being called with a newflags that does not containing VM_LOCKED. This would
be treated as munlockall(). Not good. Your first check would catch
this.

The second condition would be a no-op, I think. We only look at look for MCL_RECURSIVE in mm->mcl_inherit when mcl_inherit is non-zero; and we only set mcl_inherit when MCL_INHERIT is specified. But, if the caller specified MCL_RECURSIVE, they probably intended something to happen, and since it won't, best to return an error.

Quoted 4 lines

I'll fix this up and send it out to the wider distribution that Andrew requested.

Thanks, again.

I am one of most appointee from this patch :)

--
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>