记录一次内核热补丁制作流程
最近接到下游的一个需求,要为适配某网卡修改内核的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所有引用这个结构体的地方,发现所有使用该结构体时,在函数中传的参数为该结构体的第一个成员,而不是整个结构体。如下所示。
所以制作热补丁的方案还需要继续研究,如果后面能有更好的制作热补丁的方式,可以支持结构体变化,支持头文件变化,那么对内核的修改和调试将会大大缩短开发时间。