Linux 内核设计与实现
深入理解 Linux 内核
Linux 设备驱动程序
Linux设备驱动开发详解
深入理解Linux虚拟内存管理(一)
深入理解Linux虚拟内存管理(二)
深入理解Linux虚拟内存管理(三)
深入理解Linux虚拟内存管理(四)
深入理解Linux虚拟内存管理(五)
深入理解Linux虚拟内存管理(六)
深入理解Linux虚拟内存管理(七)
深入理解Linux虚拟内存管理(八)
传送门 4.3.2 初始化一个描述符
系统中的 mm_struct 开始称为 init_mm ,它在编译时由宏 INIT_MM() 静态初始化。
// include/linux/sched.h
#define INIT_MM(name) \
{ \
mm_rb: RB_ROOT, \
pgd: swapper_pg_dir, \
mm_users: ATOMIC_INIT(2), \
mm_count: ATOMIC_INIT(1), \
mmap_sem: __RWSEM_INITIALIZER(name.mmap_sem), \
page_table_lock: SPIN_LOCK_UNLOCKED, \
mmlist: LIST_HEAD_INIT(name.mmlist), \
}
// arch/i386/kernel/init_task.c
struct mm_struct init_mm = INIT_MM(init_mm);
新 mm_struct 在建立以后,是它们父 mm_struct 的备份,并且它们由 copy_mm() 以 init_mm() 初始化的字段来复制。
这个函数为给定的进程复制一份 mm_struct 。它仅在创建一个新进程后且需要它自己的 mm_struct 时由 do_fork() 调用。
// kernel/fork.c
// 这一块重置没有被子 mm_struct 继承的字段并找到一个复制源 mm 的字段。
// 这些参数是为克隆而传入的标志位和那些复制 mm_struct 的进程。
static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
{
struct mm_struct * mm, *oldmm;
int retval;
// 初始化与内存管理相关的task_struct字段。
tsk->min_flt = tsk->maj_flt = 0;
tsk->cmin_flt = tsk->cmaj_flt = 0;
tsk->nswap = tsk->cnswap = 0;
tsk->mm = NULL;
tsk->active_mm = NULL;
/*
* Are we cloning a kernel thread?
*
* We need to steal a active VM for that..
*/
// 借用当前运行进程的mm来复制。
oldmm = current->mm;
// 一个没有mm的内核线程,所以它可以立即返回。
if (!oldmm)
return 0;
// 如果设置了 CLONE_VM 标志位,子进程将与父进程共享mm。像 pthreads 这
// 样的用户需要这样做。mm_users 字段加1, 以使mm不会过早销毁。
// good_mm 标记设置 tsk->mm 和 tsk->active_mm, 并返回成功
if (clone_flags & CLONE_VM) {
atomic_inc(&oldmm->mm_users);
mm = oldmm;
goto good_mm;
}
retval = -ENOMEM;
// 分配新的mm。
mm = allocate_mm();
if (!mm)
goto fail_nomem;
/* Copy the current MM stuff.. */
// 复制父mm, 并利用mm_init()来初始化特定进程的mm字段。
memcpy(mm, oldmm, sizeof(*mm));
if (!mm_init(mm))
goto fail_nomem;
// 为那些无法自动管理其MMU的体系结构初始化MMU上下文。
if (init_new_context(tsk,mm))
goto free_pt;
// 调用dup_mmap(),它负责复制所有VMA父进程用到的区域。
down_write(&oldmm->mmap_sem);
retval = dup_mmap(mm);
up_write(&oldmm->mmap_sem);
// 一旦成功,dup_mmap() 返回 0。如果失败,标记 free_pt 将调用 mmput() 。它将
// mm 的使用计数减 1
if (retval)
goto free_pt;
/*
* child gets a private LDT (if there was an LDT in the parent)
*/
// 基于父进程为新进程复制LDT。
copy_segments(tsk, mm);
good_mm:
// 设置新mm,active_mm 并返回成功。
tsk->mm = mm;
tsk->active_mm = mm;
return 0;
free_pt:
mmput(mm);
fail_nomem:
return retval;
}
这个函数初始化特定进程的 mm 字段。
// kernel/fork.c
#define free_mm(mm) (kmem_cache_free(mm_cachep, (mm)))
static struct mm_struct * mm_init(struct mm_struct * mm)
{
// 设置用户数为l。
atomic_set(&mm->mm_users, 1);
// 设置mm的引用计数为1。
atomic_set(&mm->mm_count, 1);
// 初始化保护VMA链表的信号量。
init_rwsem(&mm->mmap_sem);
// 初始化保护写访问的自旋锁。
mm->page_table_lock = SPIN_LOCK_UNLOCKED;
// 为该结构分配新的PGD。
mm->pgd = pgd_alloc(mm);
mm->def_flags = 0;
if (mm->pgd)
return mm;
free_mm(mm);
return NULL;
}
pgd_alloc 函数
kmem_cache_free 函数
提供了两个函数来分配一个 mm_struct。虽然有点容易混淆,但它们实际上都是一样的。allocate_mm() 将从 slab 分配器中分配一个 mm_struct 。 mm_alloc() 将分配结构,然后调用 mm_init() 来初始化。
// kernel/fork.c
#define allocate_mm() (kmem_cache_alloc(mm_cachep, SLAB_KERNEL))
// 从slab分配器分配一个mm_struct。
// kernel/fork.c
/*
* Allocate and initialize an mm_struct.
*/
struct mm_struct * mm_alloc(void)
{
struct mm_struct * mm;
// 从slab分配器分配一个mm_struct。
mm = allocate_mm();
if (mm) {
// 将结构的所有字段归0。
memset(mm, 0, sizeof(*mm));
// 进行基本的初始化。
return mm_init(mm);
}
return NULL;
}
mm 的一个新用户利用如下调用将使用计数加1:
atomic_inc( &mm->mm_users );
利用 mmput() 将使用计数减 1。如果 mm_users 计数减到 0,将调用 exit_mmap() 将所有的已映射区域删除,而且所有的页表也将会销毁,因为已经没有任何使用用户空间部分的使用者。mm_count 计数由 mmdrop() 减 1,因为页表和 VMA 的使用者都记为一个 mm_struct 使用者。在 mm_count 减到 0 时,mm_struct 将会被销毁。
// kernel/fork.c
/*
* Decrement the use count and release all resources for an mm.
*/
void mmput(struct mm_struct *mm)
{
if (atomic_dec_and_lock(&mm->mm_users, &mmlist_lock)) {
extern struct mm_struct *swap_mm;
if (swap_mm == mm)
swap_mm = list_entry(mm->mmlist.next, struct mm_struct, mmlist);
list_del(&mm->mmlist);
mmlist_nr--;
spin_unlock(&mmlist_lock);
exit_mmap(mm);
mmdrop(mm);
}
}
⇐ ⇒ ⇔ ⇆ ⇒ ⟺
①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿
⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑿⒀⒁⒂⒃⒄⒅⒆⒇
➊➋➌➍➎➏➐➑➒➓⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴
⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵
ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ
ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ
123
y = x 2 + z 3 y = x^2 + z_3 y=x2+z3
y = x 2 + z 3 + a b + b a y = x^2 + z_3 + \frac {a}{b} + \sqrt[a]{b} y=x2+z3+ba+ab
y = x 2 + z 3 (1) y = x^2 + z^3 \tag{1} y=x2+z3(1)