openVswitch(OVS)源代码分析之工作流程(哈希桶结构体的解释)

        这篇blog是专门解决前篇openVswitch(OVS)源代码分析之工作流程(哈希桶结构体的疑惑)中提到的哈希桶结构flex_array结构体成员变量含义的问题。

        引用下前篇blog中分析讨论得到的flex_array结构体成员变量的含义结论:

struct {  
            int element_size; // 这是flex_array_part结构体存放的哈希头指针的大小  
            int total_nr_elements; // 这是所有flex_array_part结构体中的哈希头指针的总个数  
            int elems_per_part; // 这是每个part指针指向的空间能存储多少个哈希头指针  
            u32 reciprocal_elems;   
            struct flex_array_part *parts[]; // 结构体指针数组,里面存放的是struct flex_array_part结构的指针  
        };  
        其实这个结论是正确的,这些结构体成员的含义就是这些意思。但前篇分析中这个结论和static inline int elements_fit_in_base(struct flex_array *fa)函数产生矛盾,这里也看下该函数的具体实现:

static inline int elements_fit_in_base(struct flex_array *fa)  
{  
// fa->element_size 根据上面的结论应该是哈希头的大小,flex_array_part结构体中存放的哈希头大小  
// fa->total_nr_elements 根据上面的结论应该是所有哈希头的总数  
// 那么data_size 就是所有存储哈希头的空间大小了,矛盾来了  
    int data_size = fa->element_size * fa->total_nr_elements;  
// FLEX_ARRAY_BASE_BYTES_LEFT是什么意思呢?  
// #define FLEX_ARRAY_BASE_BYTES_LEFT  (FLEX_ARRAY_BASE_SIZE - offsetof(struct flex_array, parts))  
// offsetof()宏用来求一个成员在结构体中的偏移量  
// 所以所有存储哈希头空间的大小和 FLEX_ARRAY_BASE_BYTES_LEFT 比较是什么意思呢?
// 我当时的判断就是element_size和total_nr_elements这两个成员变量理解错了。  
    if (data_size <= FLEX_ARRAY_BASE_BYTES_LEFT)  
        return 1;  
    return 0;  
}
        如果按照一般的思想来分析这个源代码真的有问题了,至少这个函数分析不下了。那么真正的原因是什么呢?

        首先来看下哈希桶内存申请函数(在上篇中有分析)其中传过来的分别为:elements = sizeof(struct hlist*)和total = 1024(宏定义而来);

        再看看上面这个函数的实现:data_size = element_size * total_nr_elements; 也即是 data_size = elements * total;带入数据得:data_size = 4 * 1024 = 4096(因为两个参数一个是宏定义的,对整个项目来说是不变的;另外一个也一样是不会变的。所以可以当做常量带入去应验下);

        那么现在来看看if判断语句:data_size <= (4096 - 4*4);因为根据上面的flex_array结构体成员变量可以知道:有3个int型成员和一个u32类型的成员。所以得到parts前有 4*4个字节。用一个页的大小减去到parts成员前的字节为:4096 - 4*4;

        最后把所有数据带入可以得到:4096 <= (4096 - 4*4);那么这个条件肯定是恒不成立的。所以这个函数就是多余的了,因为data_size的值是一定为4096的,不管flex_array结构中成员变量代表什么意思。而FLEX_ARRAY_BASE_BYTES_LEFT也是一定不变的。

        得到上面的结论其实离真相就比较接近了,可以想象得到一个由这么多顶尖的程序员设计出来的项目,不太可能会出现一个冗余的函数,而且在flex_array.c中大量的使用。那么这个函数一定有其他用处,我想了很多种可能,也反复的分析flex_array.c和flex_array.h中的源代码,最后我得到一种猜想:就是当这个项目中所要的最大元素数非常小,就是说根据需求total不需要1024,不要那么大呢? 

        猜想:需要的流表项链表头结点比较少(total_nr_elements < 1024),那么不需要分配一个parts指针(一个parts数组指针元素有一个页大小的空间)来存储,如果total_nr_elements不大于1020,就没必要分配parts指针了,直接在flex_array结构体(该结构体的大小为一个页,有3个int型和1个u32成员,所以剩下的就是1020 * 4个字节了)中存储就得了。

        下面来验证下这个猜想,来分析调用了static inline int elements_fit_in_base(struct flex_array *fa)函数的各个代码:

if (elements_fit_in_base(fa))
		part = (struct flex_array_part *)&fa->parts[0];
else {
		part_nr = fa_element_to_part_nr(fa, element_nr);
		part = __fa_get_part(fa, part_nr, flags);
		if (!part)
			return -ENOMEM;
	}
        这段代码在很多函数中都有,可以看int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,gfp_t flags);数据拷贝函数的具体实现。该代码中调用了elements_fit_in_base(fa)来判断,如果成立,也就是说total_nr_elements不大于1020;那么直接用数组头元素的地址来强转为需要的结构体,即是直接在数组头元素存储的地方开始操作,而不是数组头元素指向的地方开始操作。说明了数据就是存储在flex_array结构体中。

        下面来看另外一段代码:

void flex_array_free_parts(struct flex_array *fa)
{
	int part_nr;

	if (elements_fit_in_base(fa))
		return;
	for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++)
		kfree(fa->parts[part_nr]);
}
         看这段代码大概就知道是用来释放parts内存的。该代码中调用了elements_fit_in_base(fa),如果成立,也就是说total_nr_elements不大于1020;那么就直接返回,什么都不执行。这就暗示了这个项目中根本就没有申请parts内存,所有的流表项链表头结点都是存放在flex_array结构体中的。再看下行的for循环,是从0开始的,更能说明如果total_nr_elements大于1020就一定得申请parts内存。

        还有其他代码中调用了该函数,就不一一列证了。就目前为止来说这个猜想还是比较符合源代码的,我不能百分百的说这个猜想是正确的,希望有兴趣的朋友可以分析下。当然我也在找各种途径去分析这个矛盾和猜想。 

        转载请注明作者和原文出处,原文地址: http://blog.csdn.net/yuzhihui_no1/article/details/39939241
        分析得比较匆促,若有不正确之处,望大家指正,共同学习!谢谢!!!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值