Linux的UTS命名空间
在上一篇博客里面介绍了Linux命名空间的使用,本博客更新的博客中更新下关于linuxUTS命名空间的介绍以及使用方式;
UTS命名空间,是关于linux主机命名或者内核版本命名的一套命名空间,在此命名空间中用户感知的是一个单独命名的的linux主机名称,注意:仅仅是主机名称,如果没有结合其他命名空间操作的话,用户是感知不到一个单独的主机名称的;
一下是我学习linux的UTS命名空间的一些思路:
1. UTS命名空间在用户层怎么使用;
2. UTS命名空间在内核中的应用;
3. UTS命名空间怎么和用户的PID结合的;
我会根据以上三个问题一一介绍,可能第二点放在第三点之后讲解,这样组织结构更加清晰;
**
1.UTS命名空间在用户层怎么使用
**
这一点在我的《linux命名空间(namespace)学习(一)》中博客中有具体的使用方式,在此不赘述;
**
2.UTS命名空间怎么和用户的PID结合的;
**
UTS命名空间和用户空间和用户PID结合的方式这句话可能有点绕,如果换句话说:UTS命名空间在内核中的task_struct的表示方式,这句话就好多了。task_struct结构在内核中是表示一个唯一PID的一种方式,在内核中task_struct指向总体命名空间的struct nsproxy *nsproxy;结构和所有命名空间建立联系的。而struct nsproxy * nsproxy和内核中的所有类型的命名空间建立联系;
其中和内核UTS命名空间的数据联系结构如下:
如上图所示的流程图可以看出task_struct通过nsproxy指针一步可以找到utsnamspace结构。之后对与utsnamespace读写操操作;
数据结构如下:
struct task_struct{
......
struct nsproxy * nsproxy;
......
};
struct nsproxy {
atomic_t count;
struct uts_namespace *uts_ns;
struct ipc_namespace *ipc_ns;
struct mnt_namespace *mnt_ns;
struct pid_namespace *pid_ns;
struct net *net_ns;
};
struct uts_namespace{
struct kref kref;
struct new_utsname name;
struct user_namespace *user_ns;
};
**
3.UTS命名空间在内核中的应用
**
关于UTS命名空间在内核中的应用主要涉及如下几点:
1. UTS命名空间在clone带CLONE_NEWUTS标志过程中如何使用?
2. struct uts_namespace *copy_utsname(unsigned long flags,
struct task_struct *tsk)
{
struct uts_namespace *old_ns = tsk->nsproxy->uts_ns;
struct uts_namespace *new_ns;
BUG_ON(!old_ns);
get_uts_ns(old_ns);
if (!(flags & CLONE_NEWUTS))
return old_ns;
new_ns = clone_uts_ns(tsk, old_ns);
put_uts_ns(old_ns);
return new_ns;
}
先回答第一个问题,可能也是最复杂的问题: UTS命名空间在clone带CLONE_NEWUTS标志过程中如何使用?
首先我们知道在《linux命名空间(namespace)学习(一)》,如果CLONE带CLONE_NEWUTS标志,代表着创建一个新的UTS命名空间。用户子进程命名空间和主进程命名空格键看到的主机名可能是一致的,也可能不一致;主要取决于用户是否使用sethostname函数。但是这时候用户子命名空间和主进程命名空间使用的命名空间却不是同一个物理地址了,为什么呢?为了保证用户子命名空间和主进程命名空间的独立性,这样用户在设置主机名称的时候不会影响到主进程命名空间。主要由copy_utsname函数来起作用。原型如下:
struct uts_namespace *copy_utsname(unsigned long flags,
struct task_struct *tsk)
{
struct uts_namespace *old_ns = tsk->nsproxy->uts_ns;
struct uts_namespace *new_ns;
BUG_ON(!old_ns);
get_uts_ns(old_ns);
if (!(flags & CLONE_NEWUTS))
return old_ns;
new_ns = clone_uts_ns(tsk, old_ns);
put_uts_ns(old_ns);
return new_ns;
}
函数参数:
flags:clone函数调用的参数;
tsk:要克隆的主进程的task_struct;
函数返回值:
struct uts_name* 类型,返回的是UTS命名空间的地址;
函数作用:
先判断flags是否有CLONE_NEWUTS结构;
1.没有,则返回老的uts_namespace;
2.有,先申请一块内存再吧原来的uts_namespace拷贝给新的内存;
注意:在没有CLONE_NEWUTS结构情况下会把uts_namespace->kref加一,否则不加一;
以上可以看出,如果clone时候flags标志为没有CLONE_NEWUTS标志,只需要把旧的uts_namespace引用计数加一并返回就可以了,如果有CLONE_NEWUTS标志则需要申请一段内存区域并且返回就OK了。这样问题二的答案也就有了。