免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1990 | 回复: 0
打印 上一主题 下一主题

sysctl分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-12-29 11:59 |只看该作者 |倒序浏览
qiuhan
2007-7-20
1 重要数据结构
sys/sysctl.h
kern/kern_sysctl.c
SET_DECLARE(sysctl_set, struct sysctl_oid);
SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
static SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
全局变量sysctl__children,保存MIB树。其结构为:
sle_next指向兄弟节点, void指针oid_arg1指向子节点。我们总是从sysctl__children开始遍历MIB树,
不匹配时继续访问sle_next,匹配时访问其子节点,直到节点为空或者匹配节点数达到预定值或者遇到
oid_handler不为空的非叶子节点,然后调用该函数。
一般而言,非叶子节点(NODE)的oid_handler都为空,除非它想用oid_number序列来传递参数。
例如_kern_proc下的很多NODE都有oid_handler,用最后的oid_number来传递pid. 还有_sysctl下的NODE
(gdb) p *sysctl__children->slh_first
$72 = {oid_parent = 0xc0a13c40, oid_link = {sle_next = 0xc09a5f20}, oid_number = 0, oid_kind = 3221225473,
  oid_arg1 = 0xc0a12244, oid_arg2 = 0, oid_name = 0xc0934198 "sysctl", oid_handler = 0, oid_fmt = 0xc0900a9e "N",
  oid_refcnt = 0, oid_descr = 0xc092d95d "Sysctl internal magic"}
(gdb) p *sysctl__children->slh_first->oid_link->sle_next
$73 = {oid_parent = 0xc0a13c40, oid_link = {sle_next = 0xc09a5f60}, oid_number = 1, oid_kind = 3221225473,
  oid_arg1 = 0xc0a12240, oid_arg2 = 0, oid_name = 0xc092d973 "kern", oid_handler = 0, oid_fmt = 0xc0900a9e "N",
  oid_refcnt = 0, oid_descr = 0xc092d978 "High kernel, proc, limits &c"}
(gdb) p *sysctl__children->slh_first->oid_link->sle_next->oid_link->sle_next
$74 = {oid_parent = 0xc0a13c40, oid_link = {sle_next = 0xc09a5fa0}, oid_number = 2, oid_kind = 3221225473,
  oid_arg1 = 0xc0a12248, oid_arg2 = 0, oid_name = 0xc0942340 "vm", oid_handler = 0, oid_fmt = 0xc0900a9e "N",
  oid_refcnt = 0, oid_descr = 0xc092d995 "Virtual memory"}
(gdb) p *((struct sysctl_oid_list *)(sysctl__children->slh_first->oid_arg1))->slh_first
$78 = {oid_parent = 0xc0a12244, oid_link = {sle_next = 0xc09a8b40}, oid_number = 1, oid_kind = 2147483649,
  oid_arg1 = 0xc0a13ca0, oid_arg2 = 0, oid_name = 0xc093b71a "name", oid_handler = 0xc068c030 ,
  oid_fmt = 0xc0900a9e "N", oid_refcnt = 0, oid_descr = 0xc0924c8d ""}
/*
* This describes the access space for a sysctl request.  This is needed
* so that we can use the interface from the kernel or from user-space.
*/
struct sysctl_req {
    struct thread   *td;        /* used for access checking */
    int     lock;       /* locking/wiring state */
//缓冲指针,用于传递__sysctl运行的结果
    void        *oldptr;
    size_t      oldlen; //oldptr大小,由调用者传入,内核会判断该区间的读写属性
    size_t      oldidx; //已copy大小,copy过程可能多次
//为sysctl_old_kernel或者sysctl_old_user,负责写入oldptr
    int     (*oldfunc)(struct sysctl_req *, const void *, size_t);
    void        *newptr;
    size_t      newlen;
    size_t      newidx;
//为sysctl_new_kernel或者sysctl_new_user,负责把newptr拷入内核
    int     (*newfunc)(struct sysctl_req *, void *, size_t);
    size_t      validlen;//用于记录写入oldptr的大小
    int     flags;
};
由于存在kernel_sysctl和userland_sysctl,所以会有这两种函数
SLIST_HEAD(sysctl_oid_list, sysctl_oid);
/*
* This describes one "oid" in the MIB tree.  Potentially more nodes can
* be hidden behind it, expanded by the handler.
*/
struct sysctl_oid {
    struct sysctl_oid_list *oid_parent;
    SLIST_ENTRY(sysctl_oid) oid_link;
    int     oid_number;
    u_int       oid_kind;
    void        *oid_arg1;
    int     oid_arg2;
    const char  *oid_name;
    int         (*oid_handler)(SYSCTL_HANDLER_ARGS);
    const char  *oid_fmt;
    int     oid_refcnt;
    const char  *oid_descr;
};
2 __sysctl 功能
struct sysctl_args {
    int *name;
    u_int   namelen;
    void    *old;
    size_t  *oldlenp;
    void    *new;
    size_t  newlen;
};
其中,name为oid_number的整型数组,namelen为该数组长度.
__sysctl按照name遍历sysctl__children,直到第一个oid_handler不为空的
节点(可以为非叶子节点),然后以name后面未用的元素、长度以及req(包含old,
oldlenp,new和newlen作为参数调用oid_handler指向的函数。
例1:
int
sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
         size_t newlen)
{
    int name2oid_oid[2];
    int real_oid[CTL_MAXNAME+2];
    int error;
    size_t oidlen;
    name2oid_oid[0] = 0;
    name2oid_oid[1] = 3;
    oidlen = sizeof(real_oid);
//依次找到的节点为sysctl,及子节点name2oid,然后调用oid_handler指向的函数
//sysctl_sysctl_name2oid,获得name
//对应的oid序列429, 411, 820, 823, oidlen=16
    error = sysctl(name2oid_oid, 2, real_oid, &oidlen, (void *)name,
               strlen(name));
    if (error :    0xc0a508c0
(gdb) x/x 0xc0a48014
0xc0a48014 :        0xc0a50c00
(gdb) x/x 0xc0a4907c
0xc0a4907c :   0xc0a7ffcc
从上面我们可以分析得出:
1 &__start_set_sysctl_set 和 &__stop_set_sysctl_set分别标识set_sysctl_set段的开始和结束
  大小为106c, (共有1051个oid), 所以代码中有
#define SET_BEGIN(set)                          \
    (&__CONCAT(__start_set_,set))
#define SET_LIMIT(set)                          \
    (&__CONCAT(__stop_set_,set))
#define SET_FOREACH(pvar, set)                      \
    for (pvar = SET_BEGIN(set); pvar < SET_LIMIT(set); pvar++)
2 set_sysctl_set段中保存的只是指针,而具体的值却是在.data段中。例如,我们可以看到0xc0a48010指向的
  是0xc0a508c0,而该地址位于.data段中.
3 我们并没有看到显示的对__start_set_sysctl_set 或者 __stop_set_sysctl_set进行赋值,很可能是在
  内核链接时得到的[FIXME]
(gdb) macro expand  TUNABLE_INT("hw.ata.ata_dma", &ata_dma);
expands to:
    static struct tunable_int __tunable_int___LINE__ = {("hw.ata.ata_dma"), (&ata_dma),};
    static struct sysinit __Tunable_init___LINE___sys_init = {
        SI_SUB_TUNABLES, SI_ORDER_MIDDLE,
        (sysinit_cfunc_t) (sysinit_nfunc_t) tunable_int_init,
        ((void *)(&__tunable_int___LINE__))};
    static void const *const __set_sysinit_set_sym___Tunable_init___LINE___sys_init
        __attribute__((__section__("set_" "sysinit_set")))
        __attribute__((__used__)) = &__Tunable_init___LINE___sys_init;
初始化ata_dma的值.
在loader过程中会根据loader.conf等文件初始化一些环境变量,放在envp(参见loader),
其格式为(以0分割,以00结束):
name1=value10name2=value20...00
(gdb) p kern_envp
$24 = 0xc0eb5000 "LINES=24"
(gdb) x/s 0xc0eb5009
0xc0eb5009:      "acpi_load=YES"
(gdb) x/s 0xc0eb5017
0xc0eb5017:      "bootfile=kernel"
该地址在init386中传递给内核:
kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE;
在mi_startup中调用init_dynamic_kenv初始化动态内核环境变量列表kenvp
kenvp可以通过kenv(通过setenv, unsetenv)系统调用增加或减少
TUNABLE_INT通过在mi_startup中tunable_int_init,进而调用getenv_int((path), (var))
查找kenvp列表得到"hw.ata.ata_dma"的值,如果没有找到,则赋值为0
(gdb) bt
#0  name2oid (name=0xc24062e0 "security", oid=0xc89c5b58, len=0xc89c5b4c, oidpp=0xc89c5b50)
    at ../../../kern/kern_sysctl.c:696
#1  0xc068c4b1 in sysctl_sysctl_name2oid (oidp=0xc09a8b80, arg1=0x0, arg2=0, req=0xc89c5c04)
    at ../../../kern/kern_sysctl.c:736
#2  0xc068cd3b in sysctl_root (oidp=0x0, arg1=0x0, arg2=0, req=0xc89c5c04) at ../../../kern/kern_sysctl.c:1281
#3  0xc068cf3c in userland_sysctl (td=0xc89c5b4c, name=0xc89c5c74, namelen=2, old=0xc89c5c04, oldlenp=0xbfbfe998,
    inkernel=0, new=0x280cc499, newlen=3365690188, retval=0xc89c5c70, flags=-929277108) at ../../../kern/kern_sysctl.c:1380
#4  0xc068cddf in __sysctl (td=0xc23e6300, uap=0xc89c5d04) at ../../../kern/kern_sysctl.c:1315


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/41770/showart_452854.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP