Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / net / tux / mod.c
1 /*
2  * TUX - Integrated Application Protocols Layer and Object Cache
3  *
4  * Copyright (C) 2000, 2001, Ingo Molnar <mingo@redhat.com>
5  *
6  * mod.c: loading/registering of dynamic TUX modules
7  */
8
9 #include <net/tux.h>
10 #include <linux/kmod.h>
11
12 /****************************************************************
13  *      This program is free software; you can redistribute it and/or modify
14  *      it under the terms of the GNU General Public License as published by
15  *      the Free Software Foundation; either version 2, or (at your option)
16  *      any later version.
17  *
18  *      This program is distributed in the hope that it will be useful,
19  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *      GNU General Public License for more details.
22  *
23  *      You should have received a copy of the GNU General Public License
24  *      along with this program; if not, write to the Free Software
25  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  *
27  ****************************************************************/
28
29 DEFINE_SPINLOCK(tuxmodules_lock);
30 static LIST_HEAD(tuxmodules_list);
31
32 tcapi_template_t * get_first_usermodule (void)
33 {
34         tcapi_template_t *tcapi;
35         struct list_head *head, *curr, *next;
36
37         spin_lock(&tuxmodules_lock);
38         head = &tuxmodules_list;
39         next = head->next;
40
41         while ((curr = next) != head) {
42                 tcapi = list_entry(curr, tcapi_template_t, modules);
43                 next = curr->next;
44                 if (tcapi->userspace_id) {
45                         spin_unlock(&tuxmodules_lock);
46                         return tcapi;
47                 }
48         }
49         spin_unlock(&tuxmodules_lock);
50         return NULL;
51 }
52
53 static tcapi_template_t * lookup_module (const char *vfs_name)
54 {
55         tcapi_template_t *tcapi;
56         struct list_head *head, *curr, *next;
57
58         while (*vfs_name == '/')
59                 vfs_name++;
60         Dprintk("looking up TUX module {%s}.\n", vfs_name);
61         head = &tuxmodules_list;
62         next = head->next;
63
64         while ((curr = next) != head) {
65                 tcapi = list_entry(curr, tcapi_template_t, modules);
66                 next = curr->next;
67                 Dprintk("checking module {%s} == {%s}?\n", vfs_name, tcapi->vfs_name);
68                 if (!strcmp(tcapi->vfs_name, vfs_name))
69                         return tcapi;
70         }
71         return NULL;
72 }
73
74 /*
75  * Attempt to load a TUX application module.
76  * This is the slow path, we cache ('link') the module's
77  * API vector to the inode.
78  * The module loading path is serialized, and we handshake
79  * with the loaded module and fetch its API vector.
80  */
81 tcapi_template_t * lookup_tuxmodule (const char *filename)
82 {
83         tcapi_template_t *tcapi;
84
85         spin_lock(&tuxmodules_lock);
86         tcapi = lookup_module(filename);
87         if (!tcapi)
88                 Dprintk("did not find module vfs:{%s}\n", filename);
89         spin_unlock(&tuxmodules_lock);
90         return tcapi;
91 }
92
93
94 int register_tuxmodule (tcapi_template_t *tcapi)
95 {
96         int ret = -EEXIST;
97
98         spin_lock(&tuxmodules_lock);
99
100         if (lookup_module(tcapi->vfs_name)) {
101                 Dprintk("module with VFS binding '%s' already registered!\n",
102                                                  tcapi->vfs_name);
103                 goto out;
104         }
105
106         list_add(&tcapi->modules, &tuxmodules_list);
107         ret = 0;
108         Dprintk("TUX module %s registered.\n", tcapi->vfs_name);
109 out:
110         spin_unlock(&tuxmodules_lock);
111
112         return ret;
113 }
114
115 void unregister_all_tuxmodules (void)
116 {
117         tcapi_template_t *tcapi;
118         struct list_head *curr;
119
120         spin_lock(&tuxmodules_lock);
121         while (((curr = tuxmodules_list.next)) != &tuxmodules_list) {
122                 tcapi = list_entry(curr, tcapi_template_t, modules);
123                 list_del(curr);
124                 kfree(tcapi->vfs_name);
125                 kfree(tcapi);
126         }
127         spin_unlock(&tuxmodules_lock);
128 }
129
130 tcapi_template_t * unregister_tuxmodule (char *vfs_name)
131 {
132         tcapi_template_t *tcapi;
133         int err = 0;
134
135         spin_lock(&tuxmodules_lock);
136         tcapi = lookup_module(vfs_name);
137         if (!tcapi) {
138                 Dprintk("huh, module %s not registered??\n", vfs_name);
139                 err = -1;
140         } else {
141                 list_del(&tcapi->modules);
142                 Dprintk("TUX module %s unregistered.\n", vfs_name);
143         }
144         spin_unlock(&tuxmodules_lock);
145
146         return tcapi;
147 }
148
149 static int check_module_version (user_req_t *u_info)
150 {
151         int major, minor, patch, ret;
152
153         ret = copy_from_user(&major, &u_info->version_major, sizeof(int));
154         ret += copy_from_user(&minor, &u_info->version_minor, sizeof(int));
155         ret += copy_from_user(&patch, &u_info->version_patch, sizeof(int));
156         if (ret)
157                 return -EFAULT;
158
159         if ((major != TUX_MAJOR_VERSION) || (minor > TUX_MINOR_VERSION)) {
160
161                 printk(KERN_ERR "TUX: module version %d:%d incompatible with kernel version %d:%d!\n", major, minor, TUX_MAJOR_VERSION, TUX_MINOR_VERSION);
162                 return -EINVAL;
163         }
164         return 0;
165 }
166
167 int user_register_module (user_req_t *u_info)
168 {
169         int idx, len, ret;
170         tcapi_template_t *tcapi;
171         char modulename [MAX_URI_LEN+1];
172
173         ret = check_module_version(u_info);
174         if (ret)
175                 return ret;
176
177         /*
178          * Check module name length.
179          */
180         ret = strnlen_user(u_info->objectname, MAX_URI_LEN+2);
181         if (ret < 0)
182                 goto out;
183         ret = -EINVAL;
184         if (ret >= MAX_URI_LEN)
185                 goto out;
186
187         Dprintk("register user-module, %p.\n", u_info);
188         ret = strncpy_from_user(modulename, u_info->objectname, MAX_URI_LEN);
189         if (ret < 0)
190                 goto out;
191         modulename[ret] = 0;
192         Dprintk("... user-module is: {%s}.\n", modulename);
193         len = strlen(modulename);
194         if (!len)
195                 printk(KERN_ERR "no module name provided: please upgrade your TUX user-space utilities!\n");
196         if (!len || (len > MAX_URI_LEN))
197                 return -EINVAL;
198         Dprintk("... user-module len is: %d.\n", len);
199
200         ret = copy_from_user(&idx, &u_info->module_index, sizeof(int));
201         if (ret || !idx)
202                 goto out;
203         Dprintk("... user-module index is: %d.\n", idx);
204
205         ret = -ENOMEM;
206         tcapi = (tcapi_template_t *) kmalloc(sizeof(*tcapi), GFP_KERNEL);
207         if (!tcapi)
208                 goto out;
209         memset(tcapi, 0, sizeof(*tcapi));
210
211         tcapi->vfs_name = (char *) kmalloc(len+1, GFP_KERNEL);
212         if (!tcapi->vfs_name) {
213                 kfree(tcapi);
214                 goto out;
215         }
216         strcpy(tcapi->vfs_name, modulename);
217         tcapi->userspace_id = idx;
218
219         Dprintk("... registering module {%s}.\n", tcapi->vfs_name);
220         ret = register_tuxmodule(tcapi);
221 out:
222         return ret;
223 }
224
225 int user_unregister_module (user_req_t *u_info)
226 {
227         int len, ret;
228         tcapi_template_t *tcapi;
229         char modulename [MAX_URI_LEN+1];
230
231         /*
232          * Check module name length.
233          */
234         ret = strnlen_user(u_info->objectname, MAX_URI_LEN+2);
235         if (ret < 0)
236                 goto out;
237         ret = -EINVAL;
238         if (ret >= MAX_URI_LEN)
239                 goto out;
240         Dprintk("unregister user-module, %p.\n", u_info);
241         ret = strncpy_from_user(modulename, u_info->objectname, MAX_URI_LEN);
242         if (ret <= 0)
243                 goto out;
244         modulename[ret] = 0;
245         Dprintk("... user-module is: {%s}.\n", modulename);
246         len = strlen(modulename);
247         if (!len || (len > MAX_URI_LEN))
248                 return -EINVAL;
249         Dprintk("... user-module len is: %d.\n", len);
250
251         Dprintk("... unregistering module {%s}.\n", modulename);
252         tcapi = unregister_tuxmodule(modulename);
253         ret = -EINVAL;
254         if (tcapi) {
255                 ret = 0;
256                 kfree(tcapi->vfs_name);
257                 kfree(tcapi);
258         }
259 out:
260         return ret;
261 }
262