Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
a68d9759
Commit
a68d9759
authored
May 16, 2002
by
Richard Gooch
Browse files
Options
Browse Files
Download
Plain Diff
Merge atnf.csiro.au:/workaholix1/kernel/v2.5/linus
into atnf.csiro.au:/workaholix1/kernel/v2.5/rgooch-2.5
parents
6a71fc38
4cc4c697
Changes
43
Show whitespace changes
Inline
Side-by-side
Showing
43 changed files
with
342 additions
and
305 deletions
+342
-305
arch/alpha/kernel/process.c
arch/alpha/kernel/process.c
+9
-3
arch/alpha/kernel/smp.c
arch/alpha/kernel/smp.c
+4
-7
arch/arm/kernel/sys_arm.c
arch/arm/kernel/sys_arm.c
+9
-3
arch/cris/kernel/process.c
arch/cris/kernel/process.c
+9
-3
arch/i386/kernel/process.c
arch/i386/kernel/process.c
+11
-3
arch/i386/kernel/setup.c
arch/i386/kernel/setup.c
+0
-5
arch/i386/kernel/smpboot.c
arch/i386/kernel/smpboot.c
+4
-7
arch/ia64/ia32/ia32_entry.S
arch/ia64/ia32/ia32_entry.S
+2
-2
arch/ia64/kernel/entry.S
arch/ia64/kernel/entry.S
+2
-2
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/smpboot.c
+4
-7
arch/m68k/kernel/process.c
arch/m68k/kernel/process.c
+9
-3
arch/mips/kernel/smp.c
arch/mips/kernel/smp.c
+2
-3
arch/mips/kernel/syscall.c
arch/mips/kernel/syscall.c
+6
-6
arch/mips64/kernel/syscall.c
arch/mips64/kernel/syscall.c
+6
-6
arch/mips64/sgi-ip27/ip27-init.c
arch/mips64/sgi-ip27/ip27-init.c
+1
-1
arch/parisc/kernel/entry.S
arch/parisc/kernel/entry.S
+1
-1
arch/parisc/kernel/process.c
arch/parisc/kernel/process.c
+6
-3
arch/ppc/kernel/process.c
arch/ppc/kernel/process.c
+9
-3
arch/ppc/kernel/smp.c
arch/ppc/kernel/smp.c
+2
-4
arch/ppc64/kernel/process.c
arch/ppc64/kernel/process.c
+9
-3
arch/ppc64/kernel/smp.c
arch/ppc64/kernel/smp.c
+2
-4
arch/s390/kernel/process.c
arch/s390/kernel/process.c
+9
-4
arch/s390/kernel/smp.c
arch/s390/kernel/smp.c
+4
-6
arch/s390x/kernel/process.c
arch/s390x/kernel/process.c
+9
-4
arch/s390x/kernel/smp.c
arch/s390x/kernel/smp.c
+4
-6
arch/sh/kernel/process.c
arch/sh/kernel/process.c
+9
-3
arch/sparc/kernel/entry.S
arch/sparc/kernel/entry.S
+5
-4
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4d_smp.c
+1
-1
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/sun4m_smp.c
+1
-1
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/entry.S
+1
-1
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/smp.c
+1
-1
arch/x86_64/ia32/sys_ia32.c
arch/x86_64/ia32/sys_ia32.c
+9
-3
arch/x86_64/kernel/entry.S
arch/x86_64/kernel/entry.S
+1
-1
arch/x86_64/kernel/process.c
arch/x86_64/kernel/process.c
+9
-3
arch/x86_64/kernel/smpboot.c
arch/x86_64/kernel/smpboot.c
+4
-7
include/asm-generic/tlb.h
include/asm-generic/tlb.h
+56
-60
include/asm-i386/pgalloc.h
include/asm-i386/pgalloc.h
+4
-0
include/linux/mm.h
include/linux/mm.h
+0
-2
include/linux/sched.h
include/linux/sched.h
+2
-2
kernel/fork.c
kernel/fork.c
+13
-20
lib/zlib_inflate/inflate.c
lib/zlib_inflate/inflate.c
+1
-1
mm/memory.c
mm/memory.c
+44
-65
mm/mmap.c
mm/mmap.c
+48
-31
No files found.
arch/alpha/kernel/process.c
View file @
a68d9759
...
...
@@ -260,16 +260,22 @@ int
alpha_clone
(
unsigned
long
clone_flags
,
unsigned
long
usp
,
struct
switch_stack
*
swstack
)
{
struct
task_struct
*
p
;
if
(
!
usp
)
usp
=
rdusp
();
return
do_fork
(
clone_flags
,
usp
,
(
struct
pt_regs
*
)
(
swstack
+
1
),
0
);
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
usp
,
(
struct
pt_regs
*
)
(
swstack
+
1
),
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
alpha_vfork
(
struct
switch_stack
*
swstack
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
rdusp
(),
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
rdusp
(),
(
struct
pt_regs
*
)
(
swstack
+
1
),
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/alpha/kernel/smp.c
View file @
a68d9759
...
...
@@ -433,13 +433,13 @@ secondary_cpu_start(int cpuid, struct task_struct *idle)
return
0
;
}
static
int
__init
static
struct
task_struct
*
__init
fork_by_hand
(
void
)
{
/* Don't care about the contents of regs since we'll never
reschedule the forked task. */
struct
pt_regs
regs
;
return
do_fork
(
CLONE_VM
|
CLONE_
PID
,
0
,
&
regs
,
0
);
return
do_fork
(
CLONE_VM
|
CLONE_
IDLETASK
,
0
,
&
regs
,
0
);
}
/*
...
...
@@ -457,13 +457,10 @@ smp_boot_one_cpu(int cpuid, int cpunum)
the other task-y sort of data structures set up like we
wish. We can't use kernel_thread since we must avoid
rescheduling the child. */
if
(
fork_by_hand
()
<
0
)
idle
=
fork_by_hand
();
if
(
IS_ERR
(
idle
))
panic
(
"failed fork for CPU %d"
,
cpuid
);
idle
=
prev_task
(
&
init_task
);
if
(
!
idle
)
panic
(
"No idle process for CPU %d"
,
cpuid
);
init_idle
(
idle
,
cpuid
);
unhash_process
(
idle
);
...
...
arch/arm/kernel/sys_arm.c
View file @
a68d9759
...
...
@@ -238,7 +238,9 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
*/
asmlinkage
int
sys_fork
(
struct
pt_regs
*
regs
)
{
return
do_fork
(
SIGCHLD
,
regs
->
ARM_sp
,
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
regs
->
ARM_sp
,
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/* Clone a task - this clones the calling program thread.
...
...
@@ -246,14 +248,18 @@ asmlinkage int sys_fork(struct pt_regs *regs)
*/
asmlinkage
int
sys_clone
(
unsigned
long
clone_flags
,
unsigned
long
newsp
,
struct
pt_regs
*
regs
)
{
struct
task_struct
*
p
;
if
(
!
newsp
)
newsp
=
regs
->
ARM_sp
;
return
do_fork
(
clone_flags
,
newsp
,
regs
,
0
);
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
int
sys_vfork
(
struct
pt_regs
*
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
->
ARM_sp
,
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
->
ARM_sp
,
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/* sys_execve() executes a new program.
...
...
arch/cris/kernel/process.c
View file @
a68d9759
...
...
@@ -299,7 +299,9 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
asmlinkage
int
sys_fork
(
long
r10
,
long
r11
,
long
r12
,
long
r13
,
long
mof
,
long
srp
,
struct
pt_regs
*
regs
)
{
return
do_fork
(
SIGCHLD
,
rdusp
(),
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
rdusp
(),
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/* if newusp is 0, we just grab the old usp */
...
...
@@ -308,9 +310,11 @@ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
long
r12
,
long
r13
,
long
mof
,
long
srp
,
struct
pt_regs
*
regs
)
{
struct
task_struct
*
p
;
if
(
!
newusp
)
newusp
=
rdusp
();
return
do_fork
(
flags
,
newusp
,
regs
,
0
);
p
=
do_fork
(
flags
&
~
CLONE_IDLETASK
,
newusp
,
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/* vfork is a system call in i386 because of register-pressure - maybe
...
...
@@ -320,7 +324,9 @@ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
asmlinkage
int
sys_vfork
(
long
r10
,
long
r11
,
long
r12
,
long
r13
,
long
mof
,
long
srp
,
struct
pt_regs
*
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
rdusp
(),
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
rdusp
(),
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/i386/kernel/process.c
View file @
a68d9759
...
...
@@ -711,11 +711,15 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
asmlinkage
int
sys_fork
(
struct
pt_regs
regs
)
{
return
do_fork
(
SIGCHLD
,
regs
.
esp
,
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
regs
.
esp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
int
sys_clone
(
struct
pt_regs
regs
)
{
struct
task_struct
*
p
;
unsigned
long
clone_flags
;
unsigned
long
newsp
;
...
...
@@ -723,7 +727,8 @@ asmlinkage int sys_clone(struct pt_regs regs)
newsp
=
regs
.
ecx
;
if
(
!
newsp
)
newsp
=
regs
.
esp
;
return
do_fork
(
clone_flags
,
newsp
,
&
regs
,
0
);
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
@@ -738,7 +743,10 @@ asmlinkage int sys_clone(struct pt_regs regs)
*/
asmlinkage
int
sys_vfork
(
struct
pt_regs
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
esp
,
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
esp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/i386/kernel/setup.c
View file @
a68d9759
...
...
@@ -2153,11 +2153,6 @@ static void __init init_intel(struct cpuinfo_x86 *c)
strcpy
(
c
->
x86_model_id
,
p
);
#ifdef CONFIG_SMP
/* PGE CPUID bug: Pentium4 supports PGE, but seems to have SMP bugs.. */
if
(
c
->
x86
==
15
)
clear_bit
(
X86_FEATURE_PGE
,
c
->
x86_capability
);
if
(
test_bit
(
X86_FEATURE_HT
,
c
->
x86_capability
))
{
extern
int
phys_proc_id
[
NR_CPUS
];
...
...
arch/i386/kernel/smpboot.c
View file @
a68d9759
...
...
@@ -529,14 +529,14 @@ extern struct {
unsigned
short
ss
;
}
stack_start
;
static
int
__init
fork_by_hand
(
void
)
static
struct
task_struct
*
__init
fork_by_hand
(
void
)
{
struct
pt_regs
regs
;
/*
* don't care about the eip and regs settings since
* we'll never reschedule the forked task.
*/
return
do_fork
(
CLONE_VM
|
CLONE_
PID
,
0
,
&
regs
,
0
);
return
do_fork
(
CLONE_VM
|
CLONE_
IDLETASK
,
0
,
&
regs
,
0
);
}
/* which physical APIC ID maps to which logical CPU number */
...
...
@@ -822,17 +822,14 @@ static void __init do_boot_cpu (int apicid)
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
if
(
fork_by_hand
()
<
0
)
idle
=
fork_by_hand
();
if
(
IS_ERR
(
idle
))
panic
(
"failed fork for CPU %d"
,
cpu
);
/*
* We remove it from the pidhash and the runqueue
* once we got the process:
*/
idle
=
prev_task
(
&
init_task
);
if
(
!
idle
)
panic
(
"No idle process for CPU %d"
,
cpu
);
init_idle
(
idle
,
cpu
);
map_cpu_to_boot_apicid
(
cpu
,
apicid
);
...
...
arch/ia64/ia32/ia32_entry.S
View file @
a68d9759
...
...
@@ -41,7 +41,7 @@ ENTRY(ia32_clone)
mov
out3
=
16
//
stacksize
(
compensates
for
16
-
byte
scratch
area
)
adds
out2
=
IA64_SWITCH_STACK_SIZE
+
16
,
sp
//
out2
=
&
regs
zxt4
out0
=
in0
//
out0
=
clone_flags
br.call.sptk.many
rp
=
do_fork
br.call.sptk.many
rp
=
do_fork
_WITHOUT_CLONE_IDLETASK
//
FIXME
:
mask
out
CLONE_IDLETASK
from
flags
,
and
return
value
now
task_struct
*
.
.
ret0
:
.
restore
sp
adds
sp
=
IA64_SWITCH_STACK_SIZE
,
sp
//
pop
the
switch
stack
mov
ar
.
pfs
=
loc1
...
...
@@ -167,7 +167,7 @@ GLOBAL_ENTRY(sys32_fork)
mov
out1
=
0
mov
out3
=
0
adds
out2
=
IA64_SWITCH_STACK_SIZE
+
16
,
sp
//
out2
=
&
regs
br.call.sptk.few
rp
=
do_fork
br.call.sptk.few
rp
=
do_fork
_FIXME_RETURNS_TASK_STRUCT
.
ret5
:
mov
ar
.
pfs
=
loc1
.
restore
sp
adds
sp
=
IA64_SWITCH_STACK_SIZE
,
sp
//
pop
the
switch
stack
...
...
arch/ia64/kernel/entry.S
View file @
a68d9759
...
...
@@ -101,7 +101,7 @@ GLOBAL_ENTRY(sys_clone2)
mov
out3
=
in2
adds
out2
=
IA64_SWITCH_STACK_SIZE
+
16
,
sp
//
out2
=
&
regs
mov
out0
=
in0
//
out0
=
clone_flags
br.call.sptk.many
rp
=
do_fork
br.call.sptk.many
rp
=
do_fork
_WITHOUT_CLONE_IDLETASK
//
FIXME
:
mask
out
CLONE_IDLETASK
from
flags
,
and
now
returns
task_struct
*
.
.
ret1
:
.
restore
sp
adds
sp
=
IA64_SWITCH_STACK_SIZE
,
sp
//
pop
the
switch
stack
mov
ar
.
pfs
=
loc1
...
...
@@ -120,7 +120,7 @@ GLOBAL_ENTRY(sys_clone)
mov
out3
=
16
//
stacksize
(
compensates
for
16
-
byte
scratch
area
)
adds
out2
=
IA64_SWITCH_STACK_SIZE
+
16
,
sp
//
out2
=
&
regs
mov
out0
=
in0
//
out0
=
clone_flags
br.call.sptk.many
rp
=
do_fork
br.call.sptk.many
rp
=
do_fork
_WITHOUT_CLONE_IDLETASK
//
FIXME
:
mask
out
CLONE_IDLETASK
from
flags
,
and
now
return
task_struct
*
.
.
ret2
:
.
restore
sp
adds
sp
=
IA64_SWITCH_STACK_SIZE
,
sp
//
pop
the
switch
stack
mov
ar
.
pfs
=
loc1
...
...
arch/ia64/kernel/smpboot.c
View file @
a68d9759
...
...
@@ -391,14 +391,14 @@ start_secondary (void *unused)
return
cpu_idle
();
}
static
int
__init
static
struct
task_struct
*
__init
fork_by_hand
(
void
)
{
/*
* don't care about the eip and regs settings since
* we'll never reschedule the forked task.
*/
return
do_fork
(
CLONE_VM
|
CLONE_
PID
,
0
,
0
,
0
);
return
do_fork
(
CLONE_VM
|
CLONE_
IDLETASK
,
0
,
0
,
0
);
}
static
void
__init
...
...
@@ -412,17 +412,14 @@ do_boot_cpu (int sapicid)
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
if
(
fork_by_hand
()
<
0
)
idle
=
fork_by_hand
();
if
(
IS_ERR
(
idle
))
panic
(
"failed fork for CPU %d"
,
cpu
);
/*
* We remove it from the pidhash and the runqueue
* once we got the process:
*/
idle
=
prev_task
(
&
init_task
);
if
(
!
idle
)
panic
(
"No idle process for CPU %d"
,
cpu
);
init_idle
(
idle
,
cpu
);
ia64_cpu_to_sapicid
[
cpu
]
=
sapicid
;
...
...
arch/m68k/kernel/process.c
View file @
a68d9759
...
...
@@ -177,25 +177,31 @@ void flush_thread(void)
asmlinkage
int
m68k_fork
(
struct
pt_regs
*
regs
)
{
return
do_fork
(
SIGCHLD
,
rdusp
(),
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
rdusp
(),
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
int
m68k_vfork
(
struct
pt_regs
*
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
rdusp
(),
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
rdusp
(),
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
int
m68k_clone
(
struct
pt_regs
*
regs
)
{
unsigned
long
clone_flags
;
unsigned
long
newsp
;
struct
task_struct
*
p
;
/* syscall2 puts clone_flags in d1 and usp in d2 */
clone_flags
=
regs
->
d1
;
newsp
=
regs
->
d2
;
if
(
!
newsp
)
newsp
=
rdusp
();
return
do_fork
(
clone_flags
,
newsp
,
regs
,
0
);
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
copy_thread
(
int
nr
,
unsigned
long
clone_flags
,
unsigned
long
usp
,
...
...
arch/mips/kernel/smp.c
View file @
a68d9759
...
...
@@ -122,8 +122,7 @@ void __init smp_boot_cpus(void)
/* Spawn a new process normally. Grab a pointer to
its task struct so we can mess with it */
do_fork
(
CLONE_VM
|
CLONE_PID
,
0
,
&
regs
,
0
);
p
=
prev_task
(
&
init_task
);
p
=
do_fork
(
CLONE_VM
|
CLONE_IDLETASK
,
0
,
&
regs
,
0
);
/* Schedule the first task manually */
p
->
processor
=
i
;
...
...
@@ -151,7 +150,7 @@ void __init smp_boot_cpus(void)
* The following code is purely to make sure
* Linux can schedule processes on this slave.
*/
kernel_thread(0, NULL, CLONE_
PID
);
kernel_thread(0, NULL, CLONE_
IDLETASK
);
p = prev_task(&init_task);
sprintf(p->comm, "%s%d", "Idle", i);
init_tasks[i] = p;
...
...
arch/mips/kernel/syscall.c
View file @
a68d9759
...
...
@@ -95,10 +95,10 @@ sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
save_static_function
(
sys_fork
);
static_unused
int
_sys_fork
(
struct
pt_regs
regs
)
{
int
res
;
struct
task_struct
*
p
;
res
=
do_fork
(
SIGCHLD
,
regs
.
regs
[
29
],
&
regs
,
0
);
return
res
;
p
=
do_fork
(
SIGCHLD
,
regs
.
regs
[
29
],
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
...
...
@@ -107,14 +107,14 @@ static_unused int _sys_clone(struct pt_regs regs)
{
unsigned
long
clone_flags
;
unsigned
long
newsp
;
int
res
;
struct
task_struct
*
p
;
clone_flags
=
regs
.
regs
[
4
];
newsp
=
regs
.
regs
[
5
];
if
(
!
newsp
)
newsp
=
regs
.
regs
[
29
];
res
=
do_fork
(
clone_flags
,
newsp
,
&
regs
,
0
);
return
res
;
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/mips64/kernel/syscall.c
View file @
a68d9759
...
...
@@ -77,26 +77,26 @@ sys_mmap(unsigned long addr, size_t len, unsigned long prot,
asmlinkage
int
sys_fork
(
abi64_no_regargs
,
struct
pt_regs
regs
)
{
int
res
;
struct
task_struct
*
p
;
save_static
(
&
regs
);
res
=
do_fork
(
SIGCHLD
,
regs
.
regs
[
29
],
&
regs
,
0
);
return
res
;
p
=
do_fork
(
SIGCHLD
,
regs
.
regs
[
29
],
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
int
sys_clone
(
abi64_no_regargs
,
struct
pt_regs
regs
)
{
unsigned
long
clone_flags
;
unsigned
long
newsp
;
int
res
;
struct
task_struct
*
p
;
save_static
(
&
regs
);
clone_flags
=
regs
.
regs
[
4
];
newsp
=
regs
.
regs
[
5
];
if
(
!
newsp
)
newsp
=
regs
.
regs
[
29
];
res
=
do_fork
(
clone_flags
,
newsp
,
&
regs
,
0
);
return
res
;
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/mips64/sgi-ip27/ip27-init.c
View file @
a68d9759
...
...
@@ -490,7 +490,7 @@ void allowboot(void)
* The following code is purely to make sure
* Linux can schedule processes on this slave.
*/
kernel_thread
(
0
,
NULL
,
CLONE_
PID
);
kernel_thread
(
0
,
NULL
,
CLONE_
IDLETASK
);
p
=
prev_task
(
&
init_task
);
sprintf
(
p
->
comm
,
"%s%d"
,
"Idle"
,
num_cpus
);
init_tasks
[
num_cpus
]
=
p
;
...
...
arch/parisc/kernel/entry.S
View file @
a68d9759
...
...
@@ -500,7 +500,7 @@ __kernel_thread:
ldo
CLONE_VM
(%
r0
),
%
r26
/*
Force
CLONE_VM
since
only
init_mm
*/
or
%
r26
,
%
r24
,
%
r26
/*
will
have
kernel
mappings
.
*/
copy
%
r0
,
%
r25
bl
do_fork
,
%
r2
bl
do_fork
_FIXME_NOW_RETURNS_TASK_STRUCT
,
%
r2
copy
%
r1
,
%
r24
/
*
Parent
Returns
here
*/
...
...
arch/parisc/kernel/process.c
View file @
a68d9759
...
...
@@ -159,14 +159,17 @@ int
sys_clone
(
unsigned
long
clone_flags
,
unsigned
long
usp
,
struct
pt_regs
*
regs
)
{
return
do_fork
(
clone_flags
,
usp
,
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
usp
,
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
sys_vfork
(
struct
pt_regs
*
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
->
gr
[
30
],
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
->
gr
[
30
],
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
...
...
arch/ppc/kernel/process.c
View file @
a68d9759
...
...
@@ -437,22 +437,28 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
int
sys_clone
(
int
p1
,
int
p2
,
int
p3
,
int
p4
,
int
p5
,
int
p6
,
struct
pt_regs
*
regs
)
{
struct
task_struct
*
p
;
CHECK_FULL_REGS
(
regs
);
return
do_fork
(
p1
,
regs
->
gpr
[
1
],
regs
,
0
);
p
=
do_fork
(
p1
&
~
CLONE_IDLETASK
,
regs
->
gpr
[
1
],
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
sys_fork
(
int
p1
,
int
p2
,
int
p3
,
int
p4
,
int
p5
,
int
p6
,
struct
pt_regs
*
regs
)
{
struct
task_struct
*
p
;
CHECK_FULL_REGS
(
regs
);
return
do_fork
(
SIGCHLD
,
regs
->
gpr
[
1
],
regs
,
0
);
p
=
do_fork
(
SIGCHLD
,
regs
->
gpr
[
1
],
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
sys_vfork
(
int
p1
,
int
p2
,
int
p3
,
int
p4
,
int
p5
,
int
p6
,
struct
pt_regs
*
regs
)
{
struct
task_struct
*
p
;
CHECK_FULL_REGS
(
regs
);
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
->
gpr
[
1
],
regs
,
0
);
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
->
gpr
[
1
],
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
sys_execve
(
unsigned
long
a0
,
unsigned
long
a1
,
unsigned
long
a2
,
...
...
arch/ppc/kernel/smp.c
View file @
a68d9759
...
...
@@ -343,11 +343,9 @@ void __init smp_boot_cpus(void)
/* create a process for the processor */
/* only regs.msr is actually used, and 0 is OK for it */
memset
(
&
regs
,
0
,
sizeof
(
struct
pt_regs
));
if
(
do_fork
(
CLONE_VM
|
CLONE_PID
,
0
,
&
regs
,
0
)
<
0
)
p
=
do_fork
(
CLONE_VM
|
CLONE_IDLETASK
,
0
,
&
regs
,
0
);
if
(
IS_ERR
(
p
))
panic
(
"failed fork for CPU %d"
,
i
);
p
=
prev_task
(
&
init_task
);
if
(
!
p
)
panic
(
"No idle task for CPU %d"
,
i
);
init_idle
(
p
,
i
);
unhash_process
(
p
);
...
...
arch/ppc64/kernel/process.c
View file @
a68d9759
...
...
@@ -256,19 +256,25 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
int
sys_clone
(
int
p1
,
int
p2
,
int
p3
,
int
p4
,
int
p5
,
int
p6
,
struct
pt_regs
*
regs
)
{
return
do_fork
(
p1
,
regs
->
gpr
[
1
],
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
p1
&
~
CLONE_IDLETASK
,
regs
->
gpr
[
1
],
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
sys_fork
(
int
p1
,
int
p2
,
int
p3
,
int
p4
,
int
p5
,
int
p6
,
struct
pt_regs
*
regs
)
{
return
do_fork
(
SIGCHLD
,
regs
->
gpr
[
1
],
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
regs
->
gpr
[
1
],
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
sys_vfork
(
int
p1
,
int
p2
,
int
p3
,
int
p4
,
int
p5
,
int
p6
,
struct
pt_regs
*
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
->
gpr
[
1
],
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
->
gpr
[
1
],
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
int
sys_execve
(
unsigned
long
a0
,
unsigned
long
a1
,
unsigned
long
a2
,
...
...
arch/ppc64/kernel/smp.c
View file @
a68d9759
...
...
@@ -640,11 +640,9 @@ void __init smp_boot_cpus(void)
memset
(
&
regs
,
0
,
sizeof
(
struct
pt_regs
));
if
(
do_fork
(
CLONE_VM
|
CLONE_PID
,
0
,
&
regs
,
0
)
<
0
)
p
=
do_fork
(
CLONE_VM
|
CLONE_IDLETASK
,
0
,
&
regs
,
0
);
if
(
IS_ERR
(
p
))
panic
(
"failed fork for CPU %d"
,
i
);
p
=
prev_task
(
&
init_task
);
if
(
!
p
)
panic
(
"No idle task for CPU %d"
,
i
);
init_idle
(
p
,
i
);
...
...
arch/s390/kernel/process.c
View file @
a68d9759
...
...
@@ -332,19 +332,23 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
asmlinkage
int
sys_fork
(
struct
pt_regs
regs
)
{
return
do_fork
(
SIGCHLD
,
regs
.
gprs
[
15
],
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
regs
.
gprs
[
15
],
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
int
sys_clone
(
struct
pt_regs
regs
)
{
unsigned
long
clone_flags
;
unsigned
long
newsp
;
struct
task_struct
*
p
;
clone_flags
=
regs
.
gprs
[
3
];
newsp
=
regs
.
orig_gpr2
;
if
(
!
newsp
)
newsp
=
regs
.
gprs
[
15
];
return
do_fork
(
clone_flags
,
newsp
,
&
regs
,
0
);
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
@@ -359,8 +363,9 @@ asmlinkage int sys_clone(struct pt_regs regs)
*/
asmlinkage
int
sys_vfork
(
struct
pt_regs
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
gprs
[
15
],
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
gprs
[
15
],
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/s390/kernel/smp.c
View file @
a68d9759
...
...
@@ -505,13 +505,13 @@ void __init initialize_secondary(void)
{
}
static
int
__init
fork_by_hand
(
void
)
static
struct
task_struct
*
__init
fork_by_hand
(
void
)
{
struct
pt_regs
regs
;
/* don't care about the psw and regs settings since we'll never
reschedule the forked task. */
memset
(
&
regs
,
0
,
sizeof
(
struct
pt_regs
));
return
do_fork
(
CLONE_VM
|
CLONE_
PID
,
0
,
&
regs
,
0
);
return
do_fork
(
CLONE_VM
|
CLONE_
IDLETASK
,
0
,
&
regs
,
0
);
}
static
void
__init
do_boot_cpu
(
int
cpu
)
...
...
@@ -521,16 +521,14 @@ static void __init do_boot_cpu(int cpu)
/* We can't use kernel_thread since we must _avoid_ to reschedule
the child. */
if
(
fork_by_hand
()
<
0
)
idle
=
fork_by_hand
();
if
(
IS_ERR
(
idle
))
panic
(
"failed fork for CPU %d"
,
cpu
);
/*
* We remove it from the pidhash and the runqueue
* once we got the process:
*/
idle
=
prev_task
(
&
init_task
);
if
(
!
idle
)
panic
(
"No idle process for CPU %d"
,
cpu
);
idle
->
processor
=
cpu
;
idle
->
cpus_runnable
=
1
<<
cpu
;
/* we schedule the first task manually */
...
...
arch/s390x/kernel/process.c
View file @
a68d9759
...
...
@@ -331,19 +331,23 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
asmlinkage
int
sys_fork
(
struct
pt_regs
regs
)
{
return
do_fork
(
SIGCHLD
,
regs
.
gprs
[
15
],
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
regs
.
gprs
[
15
],
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
int
sys_clone
(
struct
pt_regs
regs
)
{
unsigned
long
clone_flags
;
unsigned
long
newsp
;
struct
task_struct
*
p
;
clone_flags
=
regs
.
gprs
[
3
];
newsp
=
regs
.
orig_gpr2
;
if
(
!
newsp
)
newsp
=
regs
.
gprs
[
15
];
return
do_fork
(
clone_flags
,
newsp
,
&
regs
,
0
);
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
@@ -358,8 +362,9 @@ asmlinkage int sys_clone(struct pt_regs regs)
*/
asmlinkage
int
sys_vfork
(
struct
pt_regs
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
gprs
[
15
],
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
gprs
[
15
],
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/s390x/kernel/smp.c
View file @
a68d9759
...
...
@@ -484,13 +484,13 @@ void __init initialize_secondary(void)
{
}
static
int
__init
fork_by_hand
(
void
)
static
struct
task_struct
*
__init
fork_by_hand
(
void
)
{
struct
pt_regs
regs
;
/* don't care about the psw and regs settings since we'll never
reschedule the forked task. */
memset
(
&
regs
,
0
,
sizeof
(
struct
pt_regs
));
return
do_fork
(
CLONE_VM
|
CLONE_
PID
,
0
,
&
regs
,
0
);
return
do_fork
(
CLONE_VM
|
CLONE_
IDLETASK
,
0
,
&
regs
,
0
);
}
static
void
__init
do_boot_cpu
(
int
cpu
)
...
...
@@ -500,16 +500,14 @@ static void __init do_boot_cpu(int cpu)
/* We can't use kernel_thread since we must _avoid_ to reschedule
the child. */
if
(
fork_by_hand
()
<
0
)
idle
=
fork_by_hand
();
if
(
IS_ERR
(
idle
))
panic
(
"failed fork for CPU %d"
,
cpu
);
/*
* We remove it from the pidhash and the runqueue
* once we got the process:
*/
idle
=
prev_task
(
&
init_task
);
if
(
!
idle
)
panic
(
"No idle process for CPU %d"
,
cpu
);
idle
->
processor
=
cpu
;
idle
->
cpus_runnable
=
1
<<
cpu
;
/* we schedule the first task manually */
...
...
arch/sh/kernel/process.c
View file @
a68d9759
...
...
@@ -276,16 +276,20 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
unsigned
long
r6
,
unsigned
long
r7
,
struct
pt_regs
regs
)
{
return
do_fork
(
SIGCHLD
,
regs
.
regs
[
15
],
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
regs
.
regs
[
15
],
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
int
sys_clone
(
unsigned
long
clone_flags
,
unsigned
long
newsp
,
unsigned
long
r6
,
unsigned
long
r7
,
struct
pt_regs
regs
)
{
struct
task_struct
*
p
;
if
(
!
newsp
)
newsp
=
regs
.
regs
[
15
];
return
do_fork
(
clone_flags
,
newsp
,
&
regs
,
0
);
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
@@ -302,7 +306,9 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
unsigned
long
r6
,
unsigned
long
r7
,
struct
pt_regs
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
regs
[
15
],
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
regs
[
15
],
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/sparc/kernel/entry.S
View file @
a68d9759
...
...
@@ -1393,7 +1393,7 @@ flush_patch_two:
std
%
g4
,
[%
curptr
+
AOFF_task_thread
+
AOFF_thread_fork_kpsr
]
add
%
sp
,
REGWIN_SZ
,
%
o2
!
arg2
:
pt_regs
ptr
mov
0
,
%
o3
call
C_LABEL
(
do_fork
)
call
C_LABEL
(
do_fork
_FIXME_NOW_RETURNS_TASK_STRUCT
)
mov
%
l5
,
%
o7
/
*
Whee
,
kernel
threads
!
*/
...
...
@@ -1416,7 +1416,8 @@ flush_patch_three:
std
%
g4
,
[%
curptr
+
AOFF_task_thread
+
AOFF_thread_fork_kpsr
]
add
%
sp
,
REGWIN_SZ
,
%
o2
!
arg2
:
pt_regs
ptr
mov
0
,
%
o3
call
C_LABEL
(
do_fork
)
/
*
FIXME
:
remove
CLONE_IDLETASK
from
flags
first
*/
call
C_LABEL
(
do_fork_WITHOUT_CLONE_IDLETASK
)
mov
%
l5
,
%
o7
/
*
Whee
,
real
vfork
!
*/
...
...
@@ -1432,9 +1433,9 @@ flush_patch_four:
sethi
%
hi
(
0x4000
| 0x0100 |
SIGCHLD
),
%
o0
mov
%
fp
,
%
o1
or
%
o0
,
%
lo
(
0x4000
| 0x0100 |
SIGCHLD
),
%
o0
sethi
%
hi
(
C_LABEL
(
do_fork
)),
%
l1
sethi
%
hi
(
C_LABEL
(
do_fork
_FIXME_NOW_RETURNS_TASK_STRUCT
)),
%
l1
mov
0
,
%
o3
jmpl
%
l1
+
%
lo
(
C_LABEL
(
do_fork
)),
%
g0
jmpl
%
l1
+
%
lo
(
C_LABEL
(
do_fork
_FIXME_NOW_RETURNS_TASK_STRUCT
)),
%
g0
add
%
sp
,
REGWIN_SZ
,
%
o2
.
align
4
...
...
arch/sparc/kernel/sun4d_smp.c
View file @
a68d9759
...
...
@@ -214,7 +214,7 @@ void __init smp4d_boot_cpus(void)
int
no
;
/* Cook up an idler for this guy. */
kernel_thread
(
start_secondary
,
NULL
,
CLONE_
PID
);
kernel_thread
(
start_secondary
,
NULL
,
CLONE_
IDLETASK
);
cpucount
++
;
...
...
arch/sparc/kernel/sun4m_smp.c
View file @
a68d9759
...
...
@@ -187,7 +187,7 @@ void __init smp4m_boot_cpus(void)
int
timeout
;
/* Cook up an idler for this guy. */
kernel_thread
(
start_secondary
,
NULL
,
CLONE_
PID
);
kernel_thread
(
start_secondary
,
NULL
,
CLONE_
IDLETASK
);
cpucount
++
;
...
...
arch/sparc64/kernel/entry.S
View file @
a68d9759
...
...
@@ -1429,7 +1429,7 @@ sys_fork: clr %o1
sys_clone
:
flushw
movrz
%
o1
,
%
fp
,
%
o1
mov
0
,
%
o3
ba
,
pt
%
xcc
,
do_fork
ba
,
pt
%
xcc
,
do_fork
_FIXME_NOW_RETURNS_TASK_STRUCT
add
%
sp
,
STACK_BIAS
+
REGWIN_SZ
,
%
o2
ret_from_syscall
:
/
*
Clear
SPARC_FLAG_NEWCHILD
,
switch_to
leaves
thread
.
flags
in
...
...
arch/sparc64/kernel/smp.c
View file @
a68d9759
...
...
@@ -268,7 +268,7 @@ void __init smp_boot_cpus(void)
int
no
;
prom_printf
(
"Starting CPU %d... "
,
i
);
kernel_thread
(
NULL
,
NULL
,
CLONE_
PID
);
kernel_thread
(
NULL
,
NULL
,
CLONE_
IDLETASK
);
cpucount
++
;
p
=
prev_task
(
&
init_task
);
...
...
arch/x86_64/ia32/sys_ia32.c
View file @
a68d9759
...
...
@@ -2683,14 +2683,18 @@ int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
asmlinkage
int
sys32_fork
(
struct
pt_regs
regs
)
{
return
do_fork
(
SIGCHLD
,
regs
.
rsp
,
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
regs
.
rsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
int
sys32_clone
(
unsigned
int
clone_flags
,
unsigned
int
newsp
,
struct
pt_regs
regs
)
{
struct
task_struct
*
p
;
if
(
!
newsp
)
newsp
=
regs
.
rsp
;
return
do_fork
(
clone_flags
,
newsp
,
&
regs
,
0
);
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
@@ -2705,7 +2709,9 @@ asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct
*/
asmlinkage
int
sys32_vfork
(
struct
pt_regs
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
rsp
,
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
rsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/x86_64/kernel/entry.S
View file @
a68d9759
...
...
@@ -570,7 +570,7 @@ ENTRY(kernel_thread)
movq
%
rsp
,
%
rdx
#
clone
now
call
do_fork
call
do_fork
_FIXME_NOW_RETURNS_TASK_STRUCT
#
save
retval
on
the
stack
so
it
's popped before `ret`
movq
%
rax
,
RAX
(%
rsp
)
...
...
arch/x86_64/kernel/process.c
View file @
a68d9759
...
...
@@ -608,14 +608,18 @@ void set_personality_64bit(void)
asmlinkage
long
sys_fork
(
struct
pt_regs
regs
)
{
return
do_fork
(
SIGCHLD
,
regs
.
rsp
,
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
SIGCHLD
,
regs
.
rsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
asmlinkage
long
sys_clone
(
unsigned
long
clone_flags
,
unsigned
long
newsp
,
struct
pt_regs
regs
)
{
struct
task_struct
*
p
;
if
(
!
newsp
)
newsp
=
regs
.
rsp
;
return
do_fork
(
clone_flags
,
newsp
,
&
regs
,
0
);
p
=
do_fork
(
clone_flags
&
~
CLONE_IDLETASK
,
newsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
@@ -630,7 +634,9 @@ asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct
*/
asmlinkage
long
sys_vfork
(
struct
pt_regs
regs
)
{
return
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
rsp
,
&
regs
,
0
);
struct
task_struct
*
p
;
p
=
do_fork
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
regs
.
rsp
,
&
regs
,
0
);
return
IS_ERR
(
p
)
?
PTR_ERR
(
p
)
:
p
->
pid
;
}
/*
...
...
arch/x86_64/kernel/smpboot.c
View file @
a68d9759
...
...
@@ -476,14 +476,14 @@ void __init initialize_secondary(void)
extern
volatile
unsigned
long
init_rsp
;
extern
void
(
*
initial_code
)(
void
);
static
int
__init
fork_by_hand
(
void
)
static
struct
task_struct
*
__init
fork_by_hand
(
void
)
{
struct
pt_regs
regs
;
/*
* don't care about the rip and regs settings since
* we'll never reschedule the forked task.
*/
return
do_fork
(
CLONE_VM
|
CLONE_
PID
,
0
,
&
regs
,
0
);
return
do_fork
(
CLONE_VM
|
CLONE_
IDLETASK
,
0
,
&
regs
,
0
);
}
#if APIC_DEBUG
...
...
@@ -538,17 +538,14 @@ static void __init do_boot_cpu (int apicid)
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
if
(
fork_by_hand
()
<
0
)
idle
=
fork_by_hand
();
if
(
IS_ERR
(
idle
))
panic
(
"failed fork for CPU %d"
,
cpu
);
/*
* We remove it from the pidhash and the runqueue
* once we got the process:
*/
idle
=
prev_task
(
&
init_task
);
if
(
!
idle
)
panic
(
"No idle process for CPU %d"
,
cpu
);
init_idle
(
idle
,
cpu
);
x86_cpu_to_apicid
[
cpu
]
=
apicid
;
...
...
include/asm-generic/tlb.h
View file @
a68d9759
...
...
@@ -16,7 +16,6 @@
#include <linux/config.h>
#include <asm/tlbflush.h>
#ifdef CONFIG_SMP
/* aim for something that fits in the L1 cache */
#define FREE_PTE_NR 508
...
...
@@ -26,90 +25,87 @@
* shootdown.
*/
typedef
struct
free_pte_ctx
{
struct
vm_area_struct
*
vma
;
struct
mm_struct
*
mm
;
unsigned
long
nr
;
/* set to ~0UL means fast mode */
unsigned
long
start_addr
,
end_addr
;
pte_t
pt
es
[
FREE_PTE_NR
];
unsigned
long
freed
;
struct
page
*
pag
es
[
FREE_PTE_NR
];
}
mmu_gather_t
;
/* Users of the generic TLB shootdown code must declare this storage space. */
extern
mmu_gather_t
mmu_gathers
[
NR_CPUS
];
/* Do me later */
#define tlb_start_vma(tlb, vma) do { } while (0)
#define tlb_end_vma(tlb, vma) do { } while (0)
/* tlb_gather_mmu
* Return a pointer to an initialized mmu_gather_t.
*/
static
inline
mmu_gather_t
*
tlb_gather_mmu
(
struct
vm_area_struct
*
vma
)
static
inline
mmu_gather_t
*
tlb_gather_mmu
(
struct
mm_struct
*
mm
)
{
mmu_gather_t
*
tlb
=
&
mmu_gathers
[
smp_processor_id
()];
struct
mm_struct
*
mm
=
vma
->
vm_mm
;
unsigned
long
nr
;
tlb
->
vma
=
vma
;
/* Use fast mode if there is only one user of this mm (this process) */
tlb
->
nr
=
(
atomic_read
(
&
(
mm
)
->
mm_users
)
==
1
)
?
~
0UL
:
0UL
;
tlb
->
mm
=
mm
;
tlb
->
freed
=
0
;
/* Use fast mode if this MM only exists on this CPU */
nr
=
~
0UL
;
#ifdef CONFIG_SMP
if
(
mm
->
cpu_vm_mask
!=
(
1
<<
smp_processor_id
()))
nr
=
0UL
;
#endif
tlb
->
nr
=
nr
;
return
tlb
;
}
/* void tlb_remove_page(mmu_gather_t *tlb, pte_t *ptep, unsigned long addr)
* Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while
* handling the additional races in SMP caused by other CPUs caching valid
* mappings in their TLBs.
*/
#define tlb_remove_page(ctxp, pte, addr) do {\
/* Handle the common case fast, first. */
\
if ((ctxp)->nr == ~0UL) {\
__free_pte(*(pte));\
pte_clear((pte));\
break;\
}\
if (!(ctxp)->nr) \
(ctxp)->start_addr = (addr);\
(ctxp)->ptes[(ctxp)->nr++] = ptep_get_and_clear(pte);\
(ctxp)->end_addr = (addr) + PAGE_SIZE;\
if ((ctxp)->nr >= FREE_PTE_NR)\
tlb_finish_mmu((ctxp), 0, 0);\
} while (0)
static
inline
void
tlb_flush_mmu
(
mmu_gather_t
*
tlb
,
unsigned
long
start
,
unsigned
long
end
)
{
unsigned
long
nr
;
flush_tlb_mm
(
tlb
->
mm
);
nr
=
tlb
->
nr
;
if
(
nr
!=
~
0UL
)
{
unsigned
long
i
;
tlb
->
nr
=
0
;
for
(
i
=
0
;
i
<
nr
;
i
++
)
free_page_and_swap_cache
(
tlb
->
pages
[
i
]);
}
}
/* tlb_finish_mmu
* Called at the end of the shootdown operation to free up any resources
* that were required. The page table lock is still held at this point.
*/
static
inline
void
tlb_finish_mmu
(
struct
free_pte_ctx
*
ctx
,
unsigned
long
start
,
unsigned
long
end
)
static
inline
void
tlb_finish_mmu
(
mmu_gather_t
*
tlb
,
unsigned
long
start
,
unsigned
long
end
)
{
unsigned
long
i
,
nr
;
/* Handle the fast case first. */
if
(
ctx
->
nr
==
~
0UL
)
{
flush_tlb_range
(
ctx
->
vma
,
start
,
end
);
return
;
}
nr
=
ctx
->
nr
;
ctx
->
nr
=
0
;
if
(
nr
)
flush_tlb_range
(
ctx
->
vma
,
ctx
->
start_addr
,
ctx
->
end_addr
);
for
(
i
=
0
;
i
<
nr
;
i
++
)
{
pte_t
pte
=
ctx
->
ptes
[
i
];
__free_pte
(
pte
);
}
int
freed
=
tlb
->
freed
;
struct
mm_struct
*
mm
=
tlb
->
mm
;
int
rss
=
mm
->
rss
;
if
(
rss
<
freed
)
freed
=
rss
;
mm
->
rss
=
rss
-
freed
;
tlb_flush_mmu
(
tlb
,
start
,
end
);
}
#else
/* The uniprocessor functions are quite simple and are inline macros in an
* attempt to get gcc to generate optimal code since this code is run on each
* page in a process at exit.
/* void tlb_remove_page(mmu_gather_t *tlb, pte_t *ptep, unsigned long addr)
* Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while
* handling the additional races in SMP caused by other CPUs caching valid
* mappings in their TLBs.
*/
typedef
struct
vm_area_struct
mmu_gather_t
;
#define tlb_gather_mmu(vma) (vma)
#define tlb_finish_mmu(tlb, start, end) flush_tlb_range(tlb, start, end)
#define tlb_remove_page(tlb, ptep, addr) do {\
pte_t __pte = *(ptep);\
pte_clear(ptep);\
__free_pte(__pte);\
} while (0)
#endif
static
inline
void
tlb_remove_page
(
mmu_gather_t
*
tlb
,
struct
page
*
page
)
{
/* Handle the common case fast, first. */
\
if
(
tlb
->
nr
==
~
0UL
)
{
free_page_and_swap_cache
(
page
);
return
;
}
tlb
->
pages
[
tlb
->
nr
++
]
=
page
;
if
(
tlb
->
nr
>=
FREE_PTE_NR
)
tlb_flush_mmu
(
tlb
,
0
,
0
);
}
#endif
/* _ASM_GENERIC__TLB_H */
include/asm-i386/pgalloc.h
View file @
a68d9759
...
...
@@ -35,6 +35,9 @@ static inline void pte_free(struct page *pte)
__free_page
(
pte
);
}
#define pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
/*
* allocating and freeing a pmd is trivial: the 1-entry pmd is
* inside the pgd, so has no extra memory associated with it.
...
...
@@ -43,6 +46,7 @@ static inline void pte_free(struct page *pte)
#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
#define pmd_free(x) do { } while (0)
#define pmd_free_tlb(tlb,x) do { } while (0)
#define pgd_populate(mm, pmd, pte) BUG()
#define check_pgt_cache() do { } while (0)
...
...
include/linux/mm.h
View file @
a68d9759
...
...
@@ -311,8 +311,6 @@ extern mem_map_t * mem_map;
extern
void
show_free_areas
(
void
);
extern
void
show_free_areas_node
(
pg_data_t
*
pgdat
);
extern
void
clear_page_tables
(
struct
mm_struct
*
,
unsigned
long
,
int
);
extern
int
fail_writepage
(
struct
page
*
);
struct
page
*
shmem_nopage
(
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
int
unused
);
struct
file
*
shmem_file_setup
(
char
*
name
,
loff_t
size
);
...
...
include/linux/sched.h
View file @
a68d9759
...
...
@@ -39,7 +39,7 @@ struct exec_domain;
#define CLONE_FS 0x00000200
/* set if fs info shared between processes */
#define CLONE_FILES 0x00000400
/* set if open files shared between processes */
#define CLONE_SIGHAND 0x00000800
/* set if signal handlers and blocked signals shared */
#define CLONE_
PID 0x00001000
/* set if pid shared
*/
#define CLONE_
IDLETASK 0x00001000
/* set if new pid should be 0 (kernel only)
*/
#define CLONE_PTRACE 0x00002000
/* set if we want to let tracing continue on the child too */
#define CLONE_VFORK 0x00004000
/* set if the parent wants the child to wake it up on mm_release */
#define CLONE_PARENT 0x00008000
/* set if we want to have the same parent as the cloner */
...
...
@@ -663,7 +663,7 @@ extern void daemonize(void);
extern
task_t
*
child_reaper
;
extern
int
do_execve
(
char
*
,
char
**
,
char
**
,
struct
pt_regs
*
);
extern
int
do_fork
(
unsigned
long
,
unsigned
long
,
struct
pt_regs
*
,
unsigned
long
);
extern
struct
task_struct
*
do_fork
(
unsigned
long
,
unsigned
long
,
struct
pt_regs
*
,
unsigned
long
);
extern
void
FASTCALL
(
add_wait_queue
(
wait_queue_head_t
*
q
,
wait_queue_t
*
wait
));
extern
void
FASTCALL
(
add_wait_queue_exclusive
(
wait_queue_head_t
*
q
,
wait_queue_t
*
wait
));
...
...
kernel/fork.c
View file @
a68d9759
...
...
@@ -136,8 +136,8 @@ static int get_pid(unsigned long flags)
struct
task_struct
*
p
;
int
pid
;
if
(
flags
&
CLONE_
PID
)
return
current
->
pid
;
if
(
flags
&
CLONE_
IDLETASK
)
return
0
;
spin_lock
(
&
lastpid_lock
);
if
((
++
last_pid
)
&
0xffff8000
)
{
...
...
@@ -608,27 +608,18 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
* For an example that's using stack_top, see
* arch/ia64/kernel/process.c.
*/
int
do_fork
(
unsigned
long
clone_flags
,
unsigned
long
stack_start
,
struct
pt_regs
*
regs
,
unsigned
long
stack_size
)
struct
task_struct
*
do_fork
(
unsigned
long
clone_flags
,
unsigned
long
stack_start
,
struct
pt_regs
*
regs
,
unsigned
long
stack_size
)
{
int
retval
;
unsigned
long
flags
;
struct
task_struct
*
p
;
struct
task_struct
*
p
=
NULL
;
struct
completion
vfork
;
if
((
clone_flags
&
(
CLONE_NEWNS
|
CLONE_FS
))
==
(
CLONE_NEWNS
|
CLONE_FS
))
return
-
EINVAL
;
retval
=
-
EPERM
;
/*
* CLONE_PID is only allowed for the initial SMP swapper
* calls
*/
if
(
clone_flags
&
CLONE_PID
)
{
if
(
current
->
pid
)
goto
fork_out
;
}
return
ERR_PTR
(
-
EINVAL
);
retval
=
-
ENOMEM
;
p
=
dup_task_struct
(
current
);
...
...
@@ -768,8 +759,7 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
*
* Let it rip!
*/
retval
=
p
->
pid
;
p
->
tgid
=
retval
;
p
->
tgid
=
p
->
pid
;
INIT_LIST_HEAD
(
&
p
->
thread_group
);
/* Need tasklist lock for parent etc handling! */
...
...
@@ -807,9 +797,12 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
* COW overhead when the child exec()s afterwards.
*/
set_need_resched
();
retval
=
0
;
fork_out:
return
retval
;
if
(
retval
)
return
ERR_PTR
(
retval
);
return
p
;
bad_fork_cleanup_namespace:
exit_namespace
(
p
);
...
...
lib/zlib_inflate/inflate.c
View file @
a68d9759
...
...
@@ -110,7 +110,7 @@ int stream_size;
#undef NEEDBYTE
#undef NEXTBYTE
#define NEEDBYTE {if(z->avail_in==0)goto empty;r=
f
;}
#define NEEDBYTE {if(z->avail_in==0)goto empty;r=
trv
;}
#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
int
ZEXPORT
zlib_inflate
(
z
,
f
)
...
...
mm/memory.c
View file @
a68d9759
...
...
@@ -71,29 +71,11 @@ static inline void copy_cow_page(struct page * from, struct page * to, unsigned
mem_map_t
*
mem_map
;
/*
* Called by TLB shootdown
*/
void
__free_pte
(
pte_t
pte
)
{
struct
page
*
page
;
unsigned
long
pfn
=
pte_pfn
(
pte
);
if
(
!
pfn_valid
(
pfn
))
return
;
page
=
pfn_to_page
(
pfn
);
if
(
PageReserved
(
page
))
return
;
if
(
pte_dirty
(
pte
))
set_page_dirty
(
page
);
free_page_and_swap_cache
(
page
);
}
/*
* Note: this doesn't free the actual pages themselves. That
* has been handled earlier when unmapping all the memory regions.
*/
static
inline
void
free_one_pmd
(
pmd_t
*
dir
)
static
inline
void
free_one_pmd
(
mmu_gather_t
*
tlb
,
pmd_t
*
dir
)
{
struct
page
*
pte
;
...
...
@@ -106,10 +88,10 @@ static inline void free_one_pmd(pmd_t * dir)
}
pte
=
pmd_page
(
*
dir
);
pmd_clear
(
dir
);
pte_free
(
pte
);
pte_free
_tlb
(
tlb
,
pte
);
}
static
inline
void
free_one_pgd
(
pgd_t
*
dir
)
static
inline
void
free_one_pgd
(
mmu_gather_t
*
tlb
,
pgd_t
*
dir
)
{
int
j
;
pmd_t
*
pmd
;
...
...
@@ -125,26 +107,26 @@ static inline void free_one_pgd(pgd_t * dir)
pgd_clear
(
dir
);
for
(
j
=
0
;
j
<
PTRS_PER_PMD
;
j
++
)
{
prefetchw
(
pmd
+
j
+
(
PREFETCH_STRIDE
/
16
));
free_one_pmd
(
pmd
+
j
);
free_one_pmd
(
tlb
,
pmd
+
j
);
}
pmd_free
(
pmd
);
pmd_free
_tlb
(
tlb
,
pmd
);
}
/*
* This function clears all user-level page tables of a process - this
* is needed by execve(), so that old pages aren't in the way.
*
* Must be called with pagetable lock held.
*/
void
clear_page_tables
(
struct
mm_struct
*
mm
,
unsigned
long
first
,
int
nr
)
void
clear_page_tables
(
mmu_gather_t
*
tlb
,
unsigned
long
first
,
int
nr
)
{
pgd_t
*
page_dir
=
mm
->
pgd
;
pgd_t
*
page_dir
=
tlb
->
mm
->
pgd
;
spin_lock
(
&
mm
->
page_table_lock
);
page_dir
+=
first
;
do
{
free_one_pgd
(
page_dir
);
free_one_pgd
(
tlb
,
page_dir
);
page_dir
++
;
}
while
(
--
nr
);
spin_unlock
(
&
mm
->
page_table_lock
);
/* keep the page table cache within bounds */
check_pgt_cache
();
...
...
@@ -340,18 +322,17 @@ static inline void forget_pte(pte_t page)
}
}
static
inline
int
zap_pte_range
(
mmu_gather_t
*
tlb
,
pmd_t
*
pmd
,
unsigned
long
address
,
unsigned
long
size
)
static
void
zap_pte_range
(
mmu_gather_t
*
tlb
,
pmd_t
*
pmd
,
unsigned
long
address
,
unsigned
long
size
)
{
unsigned
long
offset
;
pte_t
*
ptep
;
int
freed
=
0
;
if
(
pmd_none
(
*
pmd
))
return
0
;
return
;
if
(
pmd_bad
(
*
pmd
))
{
pmd_ERROR
(
*
pmd
);
pmd_clear
(
pmd
);
return
0
;
return
;
}
ptep
=
pte_offset_map
(
pmd
,
address
);
offset
=
address
&
~
PMD_MASK
;
...
...
@@ -363,49 +344,63 @@ static inline int zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long ad
if
(
pte_none
(
pte
))
continue
;
if
(
pte_present
(
pte
))
{
struct
page
*
page
;
unsigned
long
pfn
=
pte_pfn
(
pte
);
pte_clear
(
ptep
);
pfn
=
pte_pfn
(
pte
);
if
(
pfn_valid
(
pfn
))
{
page
=
pfn_to_page
(
pfn
);
if
(
!
PageReserved
(
page
))
freed
++
;
struct
page
*
page
=
pfn_to_page
(
pfn
);
if
(
!
PageReserved
(
page
))
{
if
(
pte_dirty
(
pte
))
set_page_dirty
(
page
);
tlb_remove_page
(
tlb
,
page
);
}
}
/* This will eventually call __free_pte on the pte. */
tlb_remove_page
(
tlb
,
ptep
,
address
+
offset
);
}
else
{
free_swap_and_cache
(
pte_to_swp_entry
(
pte
));
pte_clear
(
ptep
);
}
}
pte_unmap
(
ptep
-
1
);
return
freed
;
}
static
inline
int
zap_pmd_range
(
mmu_gather_t
*
tlb
,
pgd_t
*
dir
,
unsigned
long
address
,
unsigned
long
size
)
static
void
zap_pmd_range
(
mmu_gather_t
*
tlb
,
pgd_t
*
dir
,
unsigned
long
address
,
unsigned
long
size
)
{
pmd_t
*
pmd
;
unsigned
long
end
;
int
freed
;
if
(
pgd_none
(
*
dir
))
return
0
;
return
;
if
(
pgd_bad
(
*
dir
))
{
pgd_ERROR
(
*
dir
);
pgd_clear
(
dir
);
return
0
;
return
;
}
pmd
=
pmd_offset
(
dir
,
address
);
end
=
address
+
size
;
if
(
end
>
((
address
+
PGDIR_SIZE
)
&
PGDIR_MASK
))
end
=
((
address
+
PGDIR_SIZE
)
&
PGDIR_MASK
);
freed
=
0
;
do
{
freed
+=
zap_pte_range
(
tlb
,
pmd
,
address
,
end
-
address
);
zap_pte_range
(
tlb
,
pmd
,
address
,
end
-
address
);
address
=
(
address
+
PMD_SIZE
)
&
PMD_MASK
;
pmd
++
;
}
while
(
address
<
end
);
return
freed
;
}
void
unmap_page_range
(
mmu_gather_t
*
tlb
,
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
unsigned
long
end
)
{
pgd_t
*
dir
;
if
(
address
>=
end
)
BUG
();
dir
=
pgd_offset
(
vma
->
vm_mm
,
address
);
tlb_start_vma
(
tlb
,
vma
);
do
{
zap_pmd_range
(
tlb
,
dir
,
address
,
end
-
address
);
address
=
(
address
+
PGDIR_SIZE
)
&
PGDIR_MASK
;
dir
++
;
}
while
(
address
&&
(
address
<
end
));
tlb_end_vma
(
tlb
,
vma
);
}
/*
...
...
@@ -417,7 +412,6 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned
mmu_gather_t
*
tlb
;
pgd_t
*
dir
;
unsigned
long
start
=
address
,
end
=
address
+
size
;
int
freed
=
0
;
dir
=
pgd_offset
(
mm
,
address
);
...
...
@@ -432,25 +426,10 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned
BUG
();
spin_lock
(
&
mm
->
page_table_lock
);
flush_cache_range
(
vma
,
address
,
end
);
tlb
=
tlb_gather_mmu
(
vma
);
do
{
freed
+=
zap_pmd_range
(
tlb
,
dir
,
address
,
end
-
address
);
address
=
(
address
+
PGDIR_SIZE
)
&
PGDIR_MASK
;
dir
++
;
}
while
(
address
&&
(
address
<
end
));
/* this will flush any remaining tlb entries */
tlb
=
tlb_gather_mmu
(
mm
);
unmap_page_range
(
tlb
,
vma
,
address
,
end
);
tlb_finish_mmu
(
tlb
,
start
,
end
);
/*
* Update rss for the mm_struct (not necessarily current->mm)
* Notice that rss is an unsigned long.
*/
if
(
mm
->
rss
>
freed
)
mm
->
rss
-=
freed
;
else
mm
->
rss
=
0
;
spin_unlock
(
&
mm
->
page_table_lock
);
}
...
...
mm/mmap.c
View file @
a68d9759
...
...
@@ -17,7 +17,10 @@
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <asm/tlb.h>
extern
void
unmap_page_range
(
mmu_gather_t
*
,
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
unsigned
long
size
);
extern
void
clear_page_tables
(
mmu_gather_t
*
tlb
,
unsigned
long
first
,
int
nr
);
/*
* WARNING: the debugging will use recursive algorithms so never enable this
...
...
@@ -329,11 +332,11 @@ static void __vma_link(struct mm_struct * mm, struct vm_area_struct * vma, stru
static
inline
void
vma_link
(
struct
mm_struct
*
mm
,
struct
vm_area_struct
*
vma
,
struct
vm_area_struct
*
prev
,
rb_node_t
**
rb_link
,
rb_node_t
*
rb_parent
)
{
lock_vma_mappings
(
vma
);
spin_lock
(
&
mm
->
page_table_lock
);
lock_vma_mappings
(
vma
);
__vma_link
(
mm
,
vma
,
prev
,
rb_link
,
rb_parent
);
spin_unlock
(
&
mm
->
page_table_lock
);
unlock_vma_mappings
(
vma
);
spin_unlock
(
&
mm
->
page_table_lock
);
mm
->
map_count
++
;
validate_mm
(
mm
);
...
...
@@ -781,13 +784,11 @@ static struct vm_area_struct * unmap_fixup(struct mm_struct *mm,
*/
area
->
vm_end
=
addr
;
lock_vma_mappings
(
area
);
spin_lock
(
&
mm
->
page_table_lock
);
}
else
if
(
addr
==
area
->
vm_start
)
{
area
->
vm_pgoff
+=
(
end
-
area
->
vm_start
)
>>
PAGE_SHIFT
;
/* same locking considerations of the above case */
area
->
vm_start
=
end
;
lock_vma_mappings
(
area
);
spin_lock
(
&
mm
->
page_table_lock
);
}
else
{
/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */
/* Add end mapping -- leave beginning for below */
...
...
@@ -814,12 +815,10 @@ static struct vm_area_struct * unmap_fixup(struct mm_struct *mm,
* things correctly.
*/
lock_vma_mappings
(
area
);
spin_lock
(
&
mm
->
page_table_lock
);
__insert_vm_struct
(
mm
,
mpnt
);
}
__insert_vm_struct
(
mm
,
area
);
spin_unlock
(
&
mm
->
page_table_lock
);
unlock_vma_mappings
(
area
);
return
extra
;
}
...
...
@@ -837,12 +836,13 @@ static struct vm_area_struct * unmap_fixup(struct mm_struct *mm,
* "prev", if it exists, points to a vma before the one
* we just free'd - but there's no telling how much before.
*/
static
void
free_pgtables
(
struct
mm_struct
*
mm
,
struct
vm_area_struct
*
prev
,
static
void
free_pgtables
(
mmu_gather_t
*
tlb
,
struct
vm_area_struct
*
prev
,
unsigned
long
start
,
unsigned
long
end
)
{
unsigned
long
first
=
start
&
PGDIR_MASK
;
unsigned
long
last
=
end
+
PGDIR_SIZE
-
1
;
unsigned
long
start_index
,
end_index
;
struct
mm_struct
*
mm
=
tlb
->
mm
;
if
(
!
prev
)
{
prev
=
mm
->
mmap
;
...
...
@@ -877,7 +877,7 @@ static void free_pgtables(struct mm_struct * mm, struct vm_area_struct *prev,
start_index
=
pgd_index
(
first
);
end_index
=
pgd_index
(
last
);
if
(
end_index
>
start_index
)
{
clear_page_tables
(
mm
,
start_index
,
end_index
-
start_index
);
clear_page_tables
(
tlb
,
start_index
,
end_index
-
start_index
);
flush_tlb_pgtables
(
mm
,
first
&
PGDIR_MASK
,
last
&
PGDIR_MASK
);
}
}
...
...
@@ -889,6 +889,7 @@ static void free_pgtables(struct mm_struct * mm, struct vm_area_struct *prev,
*/
int
do_munmap
(
struct
mm_struct
*
mm
,
unsigned
long
addr
,
size_t
len
)
{
mmu_gather_t
*
tlb
;
struct
vm_area_struct
*
mpnt
,
*
prev
,
**
npp
,
*
free
,
*
extra
;
if
((
addr
&
~
PAGE_MASK
)
||
addr
>
TASK_SIZE
||
len
>
TASK_SIZE
-
addr
)
...
...
@@ -933,7 +934,8 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
rb_erase
(
&
mpnt
->
vm_rb
,
&
mm
->
mm_rb
);
}
mm
->
mmap_cache
=
NULL
;
/* Kill the cache. */
spin_unlock
(
&
mm
->
page_table_lock
);
tlb
=
tlb_gather_mmu
(
mm
);
/* Ok - we have the memory areas we should free on the 'free' list,
* so release them, and unmap the page range..
...
...
@@ -942,7 +944,7 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
* In that case we have to be careful with VM_DENYWRITE.
*/
while
((
mpnt
=
free
)
!=
NULL
)
{
unsigned
long
st
,
end
,
size
;
unsigned
long
st
,
end
;
struct
file
*
file
=
NULL
;
free
=
free
->
vm_next
;
...
...
@@ -950,7 +952,6 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
st
=
addr
<
mpnt
->
vm_start
?
mpnt
->
vm_start
:
addr
;
end
=
addr
+
len
;
end
=
end
>
mpnt
->
vm_end
?
mpnt
->
vm_end
:
end
;
size
=
end
-
st
;
if
(
mpnt
->
vm_flags
&
VM_DENYWRITE
&&
(
st
!=
mpnt
->
vm_start
||
end
!=
mpnt
->
vm_end
)
&&
...
...
@@ -960,12 +961,12 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
remove_shared_vm_struct
(
mpnt
);
mm
->
map_count
--
;
zap_page_range
(
mpnt
,
st
,
size
);
unmap_page_range
(
tlb
,
mpnt
,
st
,
end
);
/*
* Fix the mapping, and free the old area if it wasn't reused.
*/
extra
=
unmap_fixup
(
mm
,
mpnt
,
st
,
size
,
extra
);
extra
=
unmap_fixup
(
mm
,
mpnt
,
st
,
end
-
st
,
extra
);
if
(
file
)
atomic_inc
(
&
file
->
f_dentry
->
d_inode
->
i_writecount
);
}
...
...
@@ -975,7 +976,9 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
if
(
extra
)
kmem_cache_free
(
vm_area_cachep
,
extra
);
free_pgtables
(
mm
,
prev
,
addr
,
addr
+
len
);
free_pgtables
(
tlb
,
prev
,
addr
,
addr
+
len
);
tlb_finish_mmu
(
tlb
,
addr
,
addr
+
len
);
spin_unlock
(
&
mm
->
page_table_lock
);
return
0
;
}
...
...
@@ -1092,44 +1095,58 @@ void build_mmap_rb(struct mm_struct * mm)
/* Release all mmaps. */
void
exit_mmap
(
struct
mm_struct
*
mm
)
{
mmu_gather_t
*
tlb
;
struct
vm_area_struct
*
mpnt
;
release_segments
(
mm
);
spin_lock
(
&
mm
->
page_table_lock
);
tlb
=
tlb_gather_mmu
(
mm
);
flush_cache_mm
(
mm
);
mpnt
=
mm
->
mmap
;
while
(
mpnt
)
{
unsigned
long
start
=
mpnt
->
vm_start
;
unsigned
long
end
=
mpnt
->
vm_end
;
mm
->
map_count
--
;
remove_shared_vm_struct
(
mpnt
);
unmap_page_range
(
tlb
,
mpnt
,
start
,
end
);
mpnt
=
mpnt
->
vm_next
;
}
/* This is just debugging */
if
(
mm
->
map_count
)
BUG
();
clear_page_tables
(
tlb
,
FIRST_USER_PGD_NR
,
USER_PTRS_PER_PGD
);
tlb_finish_mmu
(
tlb
,
FIRST_USER_PGD_NR
*
PGDIR_SIZE
,
USER_PTRS_PER_PGD
*
PGDIR_SIZE
);
mpnt
=
mm
->
mmap
;
mm
->
mmap
=
mm
->
mmap_cache
=
NULL
;
mm
->
mm_rb
=
RB_ROOT
;
mm
->
rss
=
0
;
spin_unlock
(
&
mm
->
page_table_lock
);
mm
->
total_vm
=
0
;
mm
->
locked_vm
=
0
;
flush_cache_mm
(
mm
);
spin_unlock
(
&
mm
->
page_table_lock
);
/*
* Walk the list again, actually closing and freeing it
* without holding any MM locks.
*/
while
(
mpnt
)
{
struct
vm_area_struct
*
next
=
mpnt
->
vm_next
;
unsigned
long
start
=
mpnt
->
vm_start
;
unsigned
long
end
=
mpnt
->
vm_end
;
unsigned
long
size
=
end
-
start
;
if
(
mpnt
->
vm_ops
)
{
if
(
mpnt
->
vm_ops
->
close
)
mpnt
->
vm_ops
->
close
(
mpnt
);
}
mm
->
map_count
--
;
remove_shared_vm_struct
(
mpnt
);
zap_page_range
(
mpnt
,
start
,
size
);
if
(
mpnt
->
vm_file
)
fput
(
mpnt
->
vm_file
);
kmem_cache_free
(
vm_area_cachep
,
mpnt
);
mpnt
=
next
;
}
flush_tlb_mm
(
mm
);
/* This is just debugging */
if
(
mm
->
map_count
)
BUG
();
clear_page_tables
(
mm
,
FIRST_USER_PGD_NR
,
USER_PTRS_PER_PGD
);
}
/* Insert vm structure into process list sorted by address
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment