patch-2.1.23 linux/kernel/module.c
Next file: linux/kernel/printk.c
Previous file: linux/kernel/ksyms.c
Back to the patch index
Back to the overall index
- Lines: 488
- Date:
Sun Jan 26 12:07:49 1997
- Orig file:
v2.1.22/linux/kernel/module.c
- Orig date:
Wed Jan 15 19:45:46 1997
diff -u --recursive --new-file v2.1.22/linux/kernel/module.c linux/kernel/module.c
@@ -7,6 +7,8 @@
#include <linux/config.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
/*
* Originally by Anonymous (as far as I know...)
@@ -118,6 +120,7 @@
long namelen, error;
struct module *mod;
+ lock_kernel();
if (!suser()) {
error = -EPERM;
goto err0;
@@ -150,11 +153,12 @@
module_list = mod; /* link it in */
- return (unsigned long) mod;
-
+ error = (long) mod;
+ goto err0;
err1:
put_mod_name(name);
err0:
+ unlock_kernel();
return error;
}
@@ -167,14 +171,13 @@
{
struct module mod_tmp, *mod;
char *name, *n_name;
- long namelen, n_namelen, i, error;
+ long namelen, n_namelen, i, error = -EPERM;
unsigned long mod_user_size;
struct module_ref *dep;
- if (!suser()) {
- error = -EPERM;
+ lock_kernel();
+ if (!suser())
goto err0;
- }
if ((namelen = get_mod_name(name_user, &name)) < 0) {
error = namelen;
goto err0;
@@ -184,14 +187,13 @@
goto err1;
}
- /* Check for legal module header sizes. */
+ /* Check module header size. We allow a bit of slop over the
+ size we are familiar with to cope with a version of insmod
+ for a newer kernel. But don't over do it. */
if ((error = get_user(mod_user_size, &mod_user->size_of_struct)) != 0)
goto err1;
- switch (mod_user_size) {
- case sizeof(struct module):
- case &((struct module *)0L)->persist_start:
- break;
- default:
+ if (mod_user_size < (unsigned long)&((struct module *)0L)->persist_start
+ || mod_user_size > sizeof(struct module) + 16*sizeof(void*)) {
printk(KERN_ERR "init_module: Invalid module header size.\n"
KERN_ERR "A new version of the modutils is likely "
"needed.\n");
@@ -264,6 +266,11 @@
goto err2;
}
#endif
+ if (mod_member_present(mod, can_unload)
+ && mod->can_unload && !bound(mod->can_unload, 0, mod)) {
+ printk(KERN_ERR "init_module: mod->can_unload out of bounds.\n");
+ goto err2;
+ }
#undef bound
@@ -279,14 +286,12 @@
printk(KERN_ERR "init_module: changed module name to "
"`%s' from `%s'\n",
n_name, mod_tmp.name);
- error = -EINVAL;
goto err3;
}
/* Ok, that's about all the sanity we can stomach; copy the rest. */
- error = copy_from_user(mod+1, mod_user+1, mod->size-sizeof(*mod));
- if (error) {
+ if (copy_from_user(mod+1, mod_user+1, mod->size-sizeof(*mod))) {
error = -EFAULT;
goto err3;
}
@@ -301,7 +306,6 @@
if (d == mod) {
printk(KERN_ERR "init_module: self-referential "
"dependancy in mod->deps.\n");
- error = -EINVAL;
goto err3;
}
@@ -310,13 +314,15 @@
printk(KERN_ERR "init_module: found dependancy that is "
"(no longer?) a module.\n");
- error = -EINVAL;
goto err3;
found_dep:
dep->ref = mod;
dep->next_ref = d->refs;
d->refs = dep;
+ /* Being referenced by a dependant module counts as a
+ use as far as kerneld is concerned. */
+ d->flags |= MOD_USED_ONCE;
}
/* Free our temporary memory. */
@@ -327,13 +333,15 @@
mod->usecount = 1;
if (mod->init && mod->init() != 0) {
mod->usecount = 0;
- return -EBUSY;
+ error = -EBUSY;
+ goto err0;
}
mod->usecount--;
/* And set it running. */
mod->flags |= MOD_RUNNING;
- return 0;
+ error = 0;
+ goto err0;
err3:
put_mod_name(n_name);
@@ -342,6 +350,7 @@
err1:
put_mod_name(name);
err0:
+ unlock_kernel();
return error;
}
@@ -350,45 +359,53 @@
{
struct module *mod, *next;
char *name;
- long error;
+ long error = -EPERM;
+ lock_kernel();
if (!suser())
- return -EPERM;
+ goto out;
if (name_user) {
if ((error = get_mod_name(name_user, &name)) < 0)
- return error;
+ goto out;
if (error == 0) {
+ error = -EINVAL;
put_mod_name(name);
- return -EINVAL;
+ goto out;
}
+ error = -ENOENT;
if ((mod = find_module(name)) == NULL) {
put_mod_name(name);
- return -ENOENT;
+ goto out;
}
put_mod_name(name);
- if (mod->refs != NULL || mod->usecount != 0)
- return -EBUSY;
+ error = -EBUSY;
+ if (mod->refs != NULL || __MOD_IN_USE(mod))
+ goto out;
free_module(mod);
- return 0;
+ error = 0;
+ goto out;
}
/* Do automatic reaping */
for (mod = module_list; mod != &kernel_module; mod = next) {
next = mod->next;
if (mod->refs == NULL &&
- mod->usecount == 0 &&
((mod->flags
& (MOD_AUTOCLEAN|MOD_RUNNING|MOD_DELETED|MOD_USED_ONCE))
- == (MOD_AUTOCLEAN|MOD_RUNNING|MOD_USED_ONCE))) {
+ == (MOD_AUTOCLEAN|MOD_RUNNING|MOD_USED_ONCE)) &&
+ !__MOD_IN_USE(mod)) {
if (mod->flags & MOD_VISITED)
mod->flags &= ~MOD_VISITED;
else
free_module(mod);
}
}
- return 0;
+ error = 0;
+out:
+ unlock_kernel();
+ return error;
}
/* Query various bits about modules. */
@@ -418,7 +435,8 @@
return 0;
calc_space_needed:
- for (space += len; mod; mod = mod->next)
+ space += len;
+ while ((mod = mod->next) != &kernel_module)
space += strlen(mod->name)+1;
if (put_user(space, ret))
@@ -460,7 +478,8 @@
return 0;
calc_space_needed:
- for (space += len; i < mod->ndeps; ++i)
+ space += len;
+ while (++i < mod->ndeps)
space += strlen(mod->deps[i].dep->name)+1;
if (put_user(space, ret))
@@ -503,7 +522,8 @@
return 0;
calc_space_needed:
- for (space += len; ref; ref = ref->next_ref)
+ space += len;
+ while ((ref = ref->next_ref) != NULL)
space += strlen(ref->ref->name)+1;
if (put_user(space, ret))
@@ -528,15 +548,15 @@
space = mod->nsyms * 2*sizeof(void *);
- if (!access_ok(VERIFY_WRITE, buf, space))
- return -EFAULT;
-
i = len = 0;
s = mod->syms;
if (space > bufsize)
goto calc_space_needed;
+ if (!access_ok(VERIFY_WRITE, buf, space))
+ return -EFAULT;
+
bufsize -= space;
vals = (unsigned long *)buf;
strings = buf+space;
@@ -562,8 +582,8 @@
return 0;
calc_space_needed:
- for (space += len; i < mod->nsyms; ++i, ++s)
- space += strlen(s->name)+1;
+ for (; i < mod->nsyms; ++i, ++s)
+ space += strlen((++s)->name)+1;
if (put_user(space, ret))
return -EFAULT;
@@ -584,6 +604,8 @@
info.addr = (unsigned long)mod;
info.size = mod->size;
info.flags = mod->flags;
+ info.usecount = (mod_member_present(mod, can_unload)
+ && mod->can_unload ? -1 : mod->usecount);
if (copy_to_user(buf, &info, sizeof(struct module_info)))
return -EFAULT;
@@ -601,20 +623,25 @@
size_t *ret)
{
struct module *mod;
+ int err;
+ lock_kernel();
if (name_user == NULL)
mod = &kernel_module;
else {
long namelen;
char *name;
- if ((namelen = get_mod_name(name_user, &name)) < 0)
- return namelen;
+ if ((namelen = get_mod_name(name_user, &name)) < 0) {
+ err = namelen;
+ goto out;
+ }
+ err = -ENOENT;
if (namelen == 0)
mod = &kernel_module;
else if ((mod = find_module(name)) == NULL) {
put_mod_name(name);
- return -ENOENT;
+ goto out;
}
put_mod_name(name);
}
@@ -622,28 +649,38 @@
switch (which)
{
case 0:
- return 0;
+ err = 0;
+ break;
case QM_MODULES:
- return qm_modules(buf, bufsize, ret);
+ err = qm_modules(buf, bufsize, ret);
+ break;
case QM_DEPS:
- return qm_deps(mod, buf, bufsize, ret);
+ err = qm_deps(mod, buf, bufsize, ret);
+ break;
case QM_REFS:
- return qm_refs(mod, buf, bufsize, ret);
+ err = qm_refs(mod, buf, bufsize, ret);
+ break;
case QM_SYMBOLS:
- return qm_symbols(mod, buf, bufsize, ret);
+ err = qm_symbols(mod, buf, bufsize, ret);
+ break;
case QM_INFO:
- return qm_info(mod, buf, bufsize, ret);
+ err = qm_info(mod, buf, bufsize, ret);
+ break;
+ default:
+ err = -EINVAL;
+ break;
}
-
- return -EINVAL;
+out:
+ unlock_kernel();
+ return err;
}
/*
* Copy the kernel symbol table to user space. If the argument is
* NULL, just return the size of the table.
*
- * This call is depreciated in favour of query_module+QM_SYMBOLS which
- * does not arbitrarily limit the length of the symbol.
+ * This call is obsolete. New programs should use query_module+QM_SYMBOLS
+ * which does not arbitrarily limit the length of symbols.
*/
asmlinkage int
@@ -652,13 +689,14 @@
struct module *mod;
int i;
+ lock_kernel();
for (mod = module_list, i = 0; mod; mod = mod->next) {
/* include the count for the module name! */
i += mod->nsyms + 1;
}
if (table == NULL)
- return i;
+ goto out;
for (mod = module_list, i = 0; mod; mod = mod->next) {
struct kernel_sym ksym;
@@ -675,7 +713,7 @@
ksym.name[sizeof(ksym.name)-1] = '\0';
if (copy_to_user(table, &ksym, sizeof(ksym)) != 0)
- return i;
+ goto out;
++i, ++table;
if (mod->nsyms == 0)
@@ -687,10 +725,12 @@
ksym.name[sizeof(ksym.name)-1] = '\0';
if (copy_to_user(table, &ksym, sizeof(ksym)) != 0)
- return i;
+ goto out;
++i, ++table;
}
}
+out:
+ unlock_kernel();
return i;
}
@@ -771,15 +811,16 @@
long len;
const char *q;
-#define safe_copystr(str, len) \
+#define safe_copy_str(str, len) \
do { \
if (left < len) \
goto fini; \
memcpy(p, str, len); p += len, left -= len; \
} while (0)
+#define safe_copy_cstr(str) safe_copy_str(str, sizeof(str)-1)
len = strlen(mod->name);
- safe_copystr(mod->name, len);
+ safe_copy_str(mod->name, len);
if ((len = 20 - len) > 0) {
if (left < len)
@@ -790,47 +831,45 @@
}
len = sprintf(tmpstr, "%8lu", mod->size);
- safe_copystr(tmpstr, len);
+ safe_copy_str(tmpstr, len);
if (mod->flags & MOD_RUNNING) {
- len = sprintf(tmpstr, "%4lu", mod->usecount);
- safe_copystr(tmpstr, len);
+ len = sprintf(tmpstr, "%4ld",
+ (mod_member_present(mod, can_unload)
+ && mod->can_unload
+ ? -1 : mod->usecount));
+ safe_copy_str(tmpstr, len);
}
if (mod->flags & MOD_DELETED)
- q = " (deleted)";
- else if (mod->flags & MOD_RUNNING)
- q = "";
- else
- q = " (uninitialized)";
- len = strlen(q);
- safe_copystr(q, len);
-
- safe_copystr("\t", 1);
+ safe_copy_cstr(" (deleted)");
+ else if (mod->flags & MOD_RUNNING) {
+ if (mod->flags & MOD_AUTOCLEAN)
+ safe_copy_cstr(" (autoclean)");
+ if (!(mod->flags & MOD_USED_ONCE))
+ safe_copy_cstr(" (unused)");
+ } else
+ safe_copy_cstr(" (uninitialized)");
if ((ref = mod->refs) != NULL) {
- safe_copystr("[", 1);
+ safe_copy_cstr(" [");
while (1) {
q = ref->ref->name;
len = strlen(q);
- safe_copystr(q, len);
+ safe_copy_str(q, len);
if ((ref = ref->next_ref) != NULL)
- safe_copystr(" ", 1);
+ safe_copy_cstr(" ");
else
break;
}
- safe_copystr("]", 1);
- }
-
- if ((mod->flags & (MOD_RUNNING | MOD_AUTOCLEAN))
- == (MOD_RUNNING | MOD_AUTOCLEAN)) {
- safe_copystr(" (autoclean)", 12);
+ safe_copy_cstr("]");
}
- safe_copystr("\n", 1);
+ safe_copy_cstr("\n");
-#undef safe_copystr
+#undef safe_copy_str
+#undef safe_copy_cstr
}
fini:
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov