zoukankan      html  css  js  c++  java
  • 记录一次内核热补丁制作流程

    最近接到下游的一个需求,要为适配某网卡修改内核的patch制作热补丁。内核热补丁有较多的约束限制,包括不支持修改数据结构,不允许删除函数内部静态局部变量,不支持头文件修改等等。本次要修改的patch包含了头文件的修改,数据结构的变动,如果要制作热补丁就需要将这些变动尽量移动到.c文件中。本次patch涉及两处数据结构的变化,分别如下:

    +++ b/include/net/bonding.h
    @@ -173,7 +173,8 @@ struct slave {
         u8     backup:1,   /* indicates backup slave. Value corresponds with
                       BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
                inactive:1, /* indicates inactive slave */
    -           should_notify:1; /* indicateds whether the state changed */
    +           should_notify:1, /* indicates whether the state changed */
    +           should_notify_link:1; /* indicates whether the link changed */
         u8     duplex;
         u32    original_mtu;
         u32    link_failure_count;
    @@ -2249,6 +2271,12 @@ struct netdev_notifier_changeupper_info {
             struct net_device *upper_dev; /* new upper dev */
             bool master; /* is upper dev master */
             bool linking; /* is the nofication for link or unlink */
    +     void *upper_info; /* upper dev info */
    +};

        一个是在结构体中新增一个位域成员,patch中对这个位域成员有读取和写的操作。为保持结构体不变,可以通过位运算从当前字节中获取到该位置的值。对应的获取和写这个位的操作可以用宏来实现,如下所示:

    #define SET_SHOULD_NOTIFY_LINK_BIT(pslave, value) 
            (value) == 1 ? (*(char *)(&(pslave)->new_link + 1) |= 0x8) : (*(char *)(&(pslave)->new_link + 1) &= 0x7)
     
    #define GET_SHOULD_NOTIFY_LINK_BIT(pslave)  ((*(char *)(&(pslave)->new_link + 1) & 0x8) >> 3)
     

        另外一个结构体是新增了一个指向void类型的指针,搜索该patch所有引用这个结构体的地方,发现所有使用该结构体时,在函数中传的参数为该结构体的第一个成员,而不是整个结构体。如下所示。

    void netdev_upper_dev_unlink(struct net_device *dev,
                     struct net_device *upper_dev)
    {
            struct netdev_notifier_changeupper_info changeupper_info;   
            changeupper_info.upper_dev = upper_dev;
            changeupper_info.master = master;
            changeupper_info.linking = true;
    +      changeupper_info.upper_info = upper_info;
    +      ret = call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, dev,
    +                       &changeupper_info.info);

    这样就可以通过新增一个与netdev_notifier_changeupper_info 结构体相同的结构体定义, 将新增的成员upper_info传入即可,并且可以保持与原有的代码保持兼容,上述修改可以改为:

    void netdev_upper_dev_unlink(struct net_device *dev,
                     struct net_device *upper_dev)
    {
            struct netdev_notifier_changeupper_info_ext changeupper_info;    
            changeupper_info_ext.upper_dev = upper_dev;
            changeupper_info_ext.master = master;
            changeupper_info_ext.linking = true;
    +      changeupper_info_ext.upper_info = upper_info;
    +      ret = call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, dev,
    +                       &changeupper_info_ext.info);

    保持原有结构体netdev_notifier_changeupper_info 不变,新增一个netdev_notifier_changeupper_info_ext结构体。

         若要不修改结构体的定义,那么就要满足在使用这个新增成员时,可以通过原有结构体找到该成员,并且要保证所有调用的函数参数接口不变化,一般来讲要保证这些比较困难,但是netdev_notifier_changeupper_info这个结构体的原有定义,以及原有的使用方式,可扩展型很好,就比较方便修改为结构体不变化的形式,满足制作内核热补丁的条件。

         解决了这两个问题后,用这个patch制作热补丁,但热补丁没有制作成功,经过专家定位,主要问题在于,同一个patch中的修改涉及到编译到内核模块的,和编译到内核的。需要把它们进行拆分,要每个patch可以单独编译通过,完成独立的一块功能。并且还要保证修改的头文件不能又被内核模块调用,又被内核调用,否则头文件也要拆分到.c中。后面经过了各种拆分,把大量的在头文件中,或者在.c文件中定义的函数,或函数实现,挪到了引用的.c中,费了较大力气才把这个补丁给做出来了,由于拆分的代码太多,有太多的函数挪用,就给这个修改带来了较大的功能和可靠性的风险。 

        所以制作热补丁的方案还需要继续研究,如果后面能有更好的制作热补丁的方式,可以支持结构体变化,支持头文件变化,那么对内核的修改和调试将会大大缩短开发时间。
  • 相关阅读:
    PHP保留小数的相关方法
    ASP.NET Core MVC 之过滤器(Filter)
    ASP.NET Core MVC 之控制器(Controller)
    ASP.NET Core MVC 之视图组件(View Component)
    ASP.NET Core MVC 之局部视图(Partial Views)
    标签助手(TagHelper)
    ASP.NET Core MVC 之布局(Layout)
    ASP.NET Core MVC 之视图(Views)
    ASP.NET Core MVC 之模型(Model)
    九卷读书:淘宝从小到大的发展 -重读《淘宝技术这十年》
  • 原文地址:https://www.cnblogs.com/xingmuxin/p/9087200.html
Copyright © 2011-2022 走看看