[PATCH] x86_64: Use the extended RIP MSR for machine check reporting if available.
[linux-2.6] / kernel / intermodule.c
1 /* Deprecated, do not use.  Moved from module.c to here. --RR */
2
3 /* Written by Keith Owens <kaos@ocs.com.au> Oct 2000 */
4 #include <linux/module.h>
5 #include <linux/kmod.h>
6 #include <linux/spinlock.h>
7 #include <linux/list.h>
8 #include <linux/slab.h>
9
10 /* inter_module functions are always available, even when the kernel is
11  * compiled without modules.  Consumers of inter_module_xxx routines
12  * will always work, even when both are built into the kernel, this
13  * approach removes lots of #ifdefs in mainline code.
14  */
15
16 static struct list_head ime_list = LIST_HEAD_INIT(ime_list);
17 static DEFINE_SPINLOCK(ime_lock);
18 static int kmalloc_failed;
19
20 struct inter_module_entry {
21         struct list_head list;
22         const char *im_name;
23         struct module *owner;
24         const void *userdata;
25 };
26
27 /**
28  * inter_module_register - register a new set of inter module data.
29  * @im_name: an arbitrary string to identify the data, must be unique
30  * @owner: module that is registering the data, always use THIS_MODULE
31  * @userdata: pointer to arbitrary userdata to be registered
32  *
33  * Description: Check that the im_name has not already been registered,
34  * complain if it has.  For new data, add it to the inter_module_entry
35  * list.
36  */
37 void inter_module_register(const char *im_name, struct module *owner, const void *userdata)
38 {
39         struct list_head *tmp;
40         struct inter_module_entry *ime, *ime_new;
41
42         if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
43                 /* Overloaded kernel, not fatal */
44                 printk(KERN_ERR
45                         "Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
46                         im_name);
47                 kmalloc_failed = 1;
48                 return;
49         }
50         memset(ime_new, 0, sizeof(*ime_new));
51         ime_new->im_name = im_name;
52         ime_new->owner = owner;
53         ime_new->userdata = userdata;
54
55         spin_lock(&ime_lock);
56         list_for_each(tmp, &ime_list) {
57                 ime = list_entry(tmp, struct inter_module_entry, list);
58                 if (strcmp(ime->im_name, im_name) == 0) {
59                         spin_unlock(&ime_lock);
60                         kfree(ime_new);
61                         /* Program logic error, fatal */
62                         printk(KERN_ERR "inter_module_register: duplicate im_name '%s'", im_name);
63                         BUG();
64                 }
65         }
66         list_add(&(ime_new->list), &ime_list);
67         spin_unlock(&ime_lock);
68 }
69
70 /**
71  * inter_module_unregister - unregister a set of inter module data.
72  * @im_name: an arbitrary string to identify the data, must be unique
73  *
74  * Description: Check that the im_name has been registered, complain if
75  * it has not.  For existing data, remove it from the
76  * inter_module_entry list.
77  */
78 void inter_module_unregister(const char *im_name)
79 {
80         struct list_head *tmp;
81         struct inter_module_entry *ime;
82
83         spin_lock(&ime_lock);
84         list_for_each(tmp, &ime_list) {
85                 ime = list_entry(tmp, struct inter_module_entry, list);
86                 if (strcmp(ime->im_name, im_name) == 0) {
87                         list_del(&(ime->list));
88                         spin_unlock(&ime_lock);
89                         kfree(ime);
90                         return;
91                 }
92         }
93         spin_unlock(&ime_lock);
94         if (kmalloc_failed) {
95                 printk(KERN_ERR
96                         "inter_module_unregister: no entry for '%s', "
97                         "probably caused by previous kmalloc failure\n",
98                         im_name);
99                 return;
100         }
101         else {
102                 /* Program logic error, fatal */
103                 printk(KERN_ERR "inter_module_unregister: no entry for '%s'", im_name);
104                 BUG();
105         }
106 }
107
108 /**
109  * inter_module_get - return arbitrary userdata from another module.
110  * @im_name: an arbitrary string to identify the data, must be unique
111  *
112  * Description: If the im_name has not been registered, return NULL.
113  * Try to increment the use count on the owning module, if that fails
114  * then return NULL.  Otherwise return the userdata.
115  */
116 static const void *inter_module_get(const char *im_name)
117 {
118         struct list_head *tmp;
119         struct inter_module_entry *ime;
120         const void *result = NULL;
121
122         spin_lock(&ime_lock);
123         list_for_each(tmp, &ime_list) {
124                 ime = list_entry(tmp, struct inter_module_entry, list);
125                 if (strcmp(ime->im_name, im_name) == 0) {
126                         if (try_module_get(ime->owner))
127                                 result = ime->userdata;
128                         break;
129                 }
130         }
131         spin_unlock(&ime_lock);
132         return(result);
133 }
134
135 /**
136  * inter_module_get_request - im get with automatic request_module.
137  * @im_name: an arbitrary string to identify the data, must be unique
138  * @modname: module that is expected to register im_name
139  *
140  * Description: If inter_module_get fails, do request_module then retry.
141  */
142 const void *inter_module_get_request(const char *im_name, const char *modname)
143 {
144         const void *result = inter_module_get(im_name);
145         if (!result) {
146                 request_module("%s", modname);
147                 result = inter_module_get(im_name);
148         }
149         return(result);
150 }
151
152 /**
153  * inter_module_put - release use of data from another module.
154  * @im_name: an arbitrary string to identify the data, must be unique
155  *
156  * Description: If the im_name has not been registered, complain,
157  * otherwise decrement the use count on the owning module.
158  */
159 void inter_module_put(const char *im_name)
160 {
161         struct list_head *tmp;
162         struct inter_module_entry *ime;
163
164         spin_lock(&ime_lock);
165         list_for_each(tmp, &ime_list) {
166                 ime = list_entry(tmp, struct inter_module_entry, list);
167                 if (strcmp(ime->im_name, im_name) == 0) {
168                         if (ime->owner)
169                                 module_put(ime->owner);
170                         spin_unlock(&ime_lock);
171                         return;
172                 }
173         }
174         spin_unlock(&ime_lock);
175         printk(KERN_ERR "inter_module_put: no entry for '%s'", im_name);
176         BUG();
177 }
178
179 EXPORT_SYMBOL(inter_module_register);
180 EXPORT_SYMBOL(inter_module_unregister);
181 EXPORT_SYMBOL(inter_module_get_request);
182 EXPORT_SYMBOL(inter_module_put);