回到主战场INSMOD_MAIN!
1610 /* And open it. */
1611 if ((fp = gzf_open(filename, O_RDONLY)) == -1) {
1612 error("%s: %m", filename);
1613 return 1;
1614 }
1615 /* Try to prevent multiple simultaneous loads. */
1616 if (dolock)
1617 flock(fp, LOCK_EX);
gzf_open首先按压缩方式打开文件,然后在尝试非压缩方式。如果要求加锁,那就满足要求。
1618 if (!get_kernel_info(K_SYMBOLS))
1619 goto out;
函数get_kernel_info在./modutils-2.4.0/util/modstat.c中。
Insmod——get_kernel_info函数
409 int get_kernel_info(int type)
410 {
411 k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL);
412
413 #ifdef COMPAT_2_0
414 if (!k_new_syscalls)
415 return old_get_kernel_info(type);
416 #endif /* COMPAT_2_0 */
417
418 return new_get_kernel_info(type);
419 }
411行的作用是测试内核的版本,sys_query_module这个系统调用是在v2.1.x以后才加入的,如果版本比这个早,就会返回-NOSYS。new_get_kernel_info是这个函数的核心,它也在这个文件里。
Insmod——new_get_kernel_info函数
84 static int new_get_kernel_info(int type)
85 {
86 struct module_stat *modules;
87 struct module_stat *m;
88 struct module_symbol *syms;
89 struct module_symbol *s;
90 size_t ret;
91 size_t bufsize;
92 size_t nmod;
93 size_t nsyms;
94 size_t i;
95 size_t j;
96 char *module_names;
97 char *mn;
98
99 drop();
100
101 /*
102 * Collect the loaded modules
103 */
104 module_names = xmalloc(bufsize = 256);
105 while (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
106 if (errno != ENOSPC) {
107 error("QM_MODULES: %m/n");
108 return 0;
109 }
110 module_names = xrealloc(module_names, bufsize = ret);
111 }
112 module_name_list = module_names;
113 l_module_name_list = bufsize;
114 n_module_stat = nmod = ret;
115 module_stat = modules = xmalloc(nmod * sizeof(struct module_stat));
116 memset(modules, 0, nmod * sizeof(struct module_stat));
117
118 /* Collect the info from the modules */
119 for (i = 0, mn = module_names, m = modules;
120 i < nmod;
121 ++i, ++m, mn += strlen(mn) + 1) {
122 struct module_info info;
123
124 m->name = mn;
125 if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
126 if (errno == ENOENT) {
127 /* The module was removed out from underneath us. */
128 m->flags = NEW_MOD_DELETED;
129 continue;
130 }
131 /* else oops */
132 error("module %s: QM_INFO: %m", mn);
133 return 0;
134 }
135
136 m->addr = info.addr;
137
138 if (type & K_INFO) {
139 m->size = info.size;
140 m->flags = info.flags;
141 m->usecount = info.usecount;
142 m->modstruct = info.addr;
143 }
144
145 if (type & K_REFS) {
146 int mm;
147 char *mrefs;
148 char *mr;
149
150 mrefs = xmalloc(bufsize = 64);
151 while (query_module(mn, QM_REFS, mrefs, bufsize, &ret)) {
152 if (errno != ENOSPC) {
153 error("QM_REFS: %m");
154 return 1;
155 }
156 mrefs = xrealloc(mrefs, bufsize = ret);
157 }
158 for (j = 0, mr = mrefs;
159 j < ret;
160 ++j, mr += strlen(mr) + 1) {
161 for (mm = 0; mm < i; ++mm) {
162 if (strcmp(mr, module_stat[mm].name) == 0) {
163 m->nrefs += 1;
164 m->refs=xrealloc(m->refs, m->nrefs * sizeof(struct module_stat **));
165 m->refs[m->nrefs - 1] = module_stat + mm;
166 break;
167 }
168 }
169 }
170 free(mrefs);
171 }
172
173 if (type & K_SYMBOLS) { /* Want info about symbols */
174 syms = xmalloc(bufsize = 1024);
175 while (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
176 if (errno == ENOSPC) {
177 syms = xrealloc(syms, bufsize = ret);
178 continue;
179 }
180 if (errno == ENOENT) {
181 /*
182 * The module was removed out
183 * from underneath us.
184 */
185 m->flags = NEW_MOD_DELETED;
186 free(syms);
187 goto next;
188 } else {
189 error("module %s: QM_SYMBOLS: %m", mn);
190 return 0;
191 }
192 }
193 nsyms = ret;
194
195 m->nsyms = nsyms;
196 m->syms = syms;
197
198 /* Convert string offsets to string pointers */
199 for (j = 0, s = syms; j < nsyms; ++j, ++s)
200 s->name += (unsigned long) syms;
201 }
202 next:
203 }
204
205 if (type & K_SYMBOLS) { /* Want info about symbols */
206 /* Collect the kernel's symbols. */
207 syms = xmalloc(bufsize = 16 * 1024);
208 while (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
209 if (errno != ENOSPC) {
210 error("kernel: QM_SYMBOLS: %m");
211 return 0;
212 }
213 syms = xrealloc(syms, bufsize = ret);
214 }
215 nksyms = nsyms = ret;
216 ksyms = syms;
217
218 /* Convert string offsets to string pointers */
219 for (j = 0, s = syms; j < nsyms; ++j, ++s)
220 s->name += (unsigned long) syms;
221 }
222
223 return 1;
224 }
99行的drop,首先清除module_stat的内容。module_stat是个全局变量,用于保存模块信息。105行获取所有内核模块的名字。然后在119行,获取所有模块的信息,这些信息以module_info结构保存。这个结构在linux/include/linux/module.h中定义。
95 struct module_info
96 {
97 unsigned long addr;
98 unsigned long size;
99 unsigned long flags;
100 long usecount;
101 };
接下来,由于type为K_SYMBOLS,所以执行173行的if块,获取各个模块的符号信息。在205行还要查询一次模块符号信息,不过这次模块名没有指定,查的是内核模块的符号(查询模块信息时,内核模块是不被查阅的)。
在INSMOD_MAIN中接下来设置当待加载模块与内核版本不符时,要使用的前后缀。
Insmod——set_ncv_prefix函数
136 /* Only set prefix once. If set by the user, use it. If not set by the
137 * user, look for a well known kernel symbol and derive the prefix from
138 * there. Otherwise set the prefix depending on whether uts_info
139 * includes SMP or not for backwards compatibility.
140 */
141 static void set_ncv_prefix(char *prefix)
142 {
143 static char derived_prefix[256];
144 static const char *well_known_symbol[] = { "get_module_symbol_R",
145 "inter_module_get_R",
146 };
147 struct module_symbol *s;
148 int i, j, l, m, pl;
149 const char *name;
150 char *p;
151
152 if (ncv_prefix)
153 return;
154
155 if (prefix)
156 ncv_prefix = prefix;
157 else {
158 /* Extract the prefix (if any) from well known symbols */
159 for (i = 0, s = ksyms; i < nksyms; ++i, ++s) {
160 name = (char *) s->name;
161 l = strlen(name);
162 for (j = 0; j < sizeof(well_known_symbol)/sizeof(well_known_symbol[0]); ++j) {
163 m = strlen(well_known_symbol[j]);
164 if (m + 8 > l ||
165 strncmp(name, well_known_symbol[j], m))
166 continue;
167 pl = l - m - 8;
168 if (pl > sizeof(derived_prefix)-1)
169 continue; /* Prefix is wrong length */
170 /* Must end with 8 hex digits */
171 (void) strtoul(name+l-8, &p, 16);
172 if (*p == 0) {
173 strncpy(derived_prefix, name+m, pl);
174 *(derived_prefix+pl) = '/0';
175 ncv_prefix = derived_prefix;
176 break;
177 }
178 }
179 }
180 }
181 if (!ncv_prefix) {
182 p = strchr(uts_info.version, ' ');
183 if (p && *(++p) && !strncmp(p, "SMP ", 4))
184 ncv_prefix = "smp_";
185 else
186 ncv_prefix = "";
187 }
188 ncv_plen = strlen(ncv_prefix);
189 if (flag_verbose)
190 lprintf("Symbol version prefix '%s'", ncv_prefix);
191 }
ncv_prefix可由用户指定,只能设置一次。如果用户没有设定,则系统通过157~180行进行设置。规则很简单,在内核模块符号里查找以“get_module_symbol_R”和“inter_module_get_R”开头的符号(我猜‘R’应该是release的意思,所以后面跟的一定是版本信息),如果存在这样的符号而且符号的最后八个子符是16进制数字,就取这八个数字作为ncv_prefix的内容。如果找不到这样的符号(不大可能),那就看通过sys_newuname获取的版本信息,如果是SMP体系(对称多CPU),将ncv_prefix设为“smp_”,否则就认为无关紧要。
接下来INSMOD_MAIN检查待安装的模块是否已经加载。如果已经加载了,当然就不能往下走了。
1627 for (i = 0; i < n_module_stat; ++i) {
1628 if (strcmp(module_stat[i].name, m_name) == 0) {
1629 error("a module named %s already exists", m_name);
1630 goto out;
1631 }
1632 }
1633
1634 error_file = filename;
1635 if ((f = obj_load(fp, ET_REL, filename)) == NULL)
1636 goto out;