Re: [PATCH] be2net: fix adapter->big_page_size miscaculation

From: Qian Cai
Date: Mon Jul 22 2019 - 23:08:50 EST


The original issue,

https://lore.kernel.org/netdev/1562959401-19815-1-git-send-email-cai@xxxxxx/

The debugging so far seems point to that the compilers get confused by the
module sections. During module_param(), it stores â__param_rx_frag_size"
as a âstruct kernel_paramâ into the __param section. Later, load_module()
obtains all âkernel_paramâ from the __param section and compare against the
user-input module parameters from the command-line. If there is a match, it
calls params[i].ops->set(&params[I]) to replace the value. If compilers canât
see that params[i].ops->set(&params[I]) could potentially change the value
of rx_frag_size, it will wrongly optimize it as a constant.


For example (it is not
compilable yet as I have not able to extract variable from the __param section
like find_module_sections()),

#include <stdio.h>
#include <string.h>

#define __module_param_call(name, ops, arg) \
static struct kernel_param __param_##name \
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) = { \
#name, ops, { arg } }

struct kernel_param {
const char *name;
const struct kernel_param_ops *ops;
union {
int *arg;
};
};

struct kernel_param_ops {
int (*set)(const struct kernel_param *kp);
};

#define STANDARD_PARAM_DEF(name) \
int param_set_##name(const struct kernel_param *kp) \
{ \
*kp->arg = 2; \
} \
const struct kernel_param_ops param_ops_##name = { \
.set = param_set_##name, \
};

STANDARD_PARAM_DEF(ushort);
static int rx = 1;
__module_param_call(rx_frag_siz, &param_ops_ushort, &rx_frag_size);

int main(int argc, char *argv[])
{
const struct kernel_param *params = <<< Get all kernel_param from the __param section >>>;
int i;

if (__builtin_constant_p(rx_frag_size))
printf("rx_frag_size is a const.\n");

for (i = 0; i < num_param; i++) {
if (!strcmp(params[I].name, argv[1])) {
params[i].ops->set(&params[i]);
break;
}
}

printf("rx_frag_size = %d\n", rx_frag_size);

return 0;
}