Whamcloud - gitweb
This commit contains probably 92% of the striping infrastructure
[fs/lustre-release.git] / lustre / obdclass / genops.c
1 /*
2  *  linux/fs/ext2_obd/sim_obd.c
3  * Copyright (C) 2001  Cluster File Systems, Inc.
4  *
5  * This code is issued under the GNU General Public License.
6  * See the file COPYING in this distribution
7  *
8  * These are the only exported functions, they provide some generic
9  * infrastructure for managing object devices
10  *
11  */
12
13 #define DEBUG_SUBSYSTEM S_CLASS
14 #include <linux/kmod.h>   /* for request_module() */
15 #include <linux/module.h>
16 #include <linux/obd_class.h>
17 #include <linux/random.h>
18 #include <linux/slab.h>
19
20 extern struct list_head obd_types; 
21 extern struct obd_device obd_dev[MAX_OBD_DEVICES];
22 kmem_cache_t *obdo_cachep = NULL;
23 kmem_cache_t *export_cachep = NULL;
24 kmem_cache_t *import_cachep = NULL;
25
26 /*
27  * support functions: we could use inter-module communication, but this
28  * is more portable to other OS's
29  */
30 static struct obd_type *class_search_type(char *nm)
31 {
32         struct list_head *tmp;
33         struct obd_type *type;
34         CDEBUG(D_INFO, "SEARCH %s\n", nm);
35
36         tmp = &obd_types;
37         while ( (tmp = tmp->next) != &obd_types ) {
38                 type = list_entry(tmp, struct obd_type, typ_chain);
39                 CDEBUG(D_INFO, "TYP %s\n", type->typ_name);
40                 if (strlen(type->typ_name) == strlen(nm) &&
41                     strcmp(type->typ_name, nm) == 0 ) {
42                         return type;
43                 }
44         }
45         return NULL;
46 }
47
48 struct obd_type *class_nm_to_type(char *nm)
49 {
50         struct obd_type *type = class_search_type(nm);
51
52 #ifdef CONFIG_KMOD
53         if ( !type ) {
54                 if ( !request_module(nm) ) {
55                         CDEBUG(D_INFO, "Loaded module '%s'\n", nm);
56                         type = class_search_type(nm);
57                 } else {
58                         CDEBUG(D_INFO, "Can't load module '%s'\n", nm);
59                 }
60         }
61 #endif
62         return type;
63 }
64
65 int class_register_type(struct obd_ops *ops, char *nm)
66 {
67         struct obd_type *type;
68
69         ENTRY;
70
71         if (class_search_type(nm)) {
72                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
73                 RETURN(-EEXIST);
74         }
75
76         OBD_ALLOC(type, sizeof(*type));
77         if (!type)
78                 RETURN(-ENOMEM);
79         INIT_LIST_HEAD(&type->typ_chain);
80         MOD_INC_USE_COUNT;
81         list_add(&type->typ_chain, obd_types.next);
82         type->typ_ops = ops;
83         type->typ_name = nm;
84         RETURN(0);
85 }
86
87 int class_unregister_type(char *nm)
88 {
89         struct obd_type *type = class_nm_to_type(nm);
90
91         ENTRY;
92
93         if ( !type ) {
94                 CERROR("unknown obd type\n");
95                 RETURN(-EINVAL);
96         }
97
98         if ( type->typ_refcnt ) {
99                 CERROR("type %s has refcount (%d)\n", nm, type->typ_refcnt);
100                 RETURN(-EBUSY);
101         }
102
103         list_del(&type->typ_chain);
104         OBD_FREE(type, sizeof(*type));
105         MOD_DEC_USE_COUNT;
106         RETURN(0);
107 } /* class_unregister_type */
108
109 int class_name2dev(char *name)
110 {
111         int res = -1;
112         int i;
113
114         if (!name)
115             return -1;
116
117         for (i=0; i < MAX_OBD_DEVICES; i++) {
118                 struct obd_device *obd = &obd_dev[i];
119                 if (obd->obd_name && strcmp(name, obd->obd_name) == 0) {
120                         res = i;
121                         return res;
122                 }
123         }
124
125         return res;
126 }
127
128 int class_uuid2dev(char *name)
129 {
130         int res = -1;
131         int i;
132
133         for (i=0; i < MAX_OBD_DEVICES; i++) {
134                 struct obd_device *obd = &obd_dev[i];
135                 if (obd->obd_name && strncmp(name, obd->obd_uuid, 37) == 0) {
136                         res = i;
137                         return res;
138                 }
139         }
140
141         return res;
142 }
143
144
145 struct obd_device *class_uuid2obd(char *name)
146 {
147         int i;
148
149         for (i=0; i < MAX_OBD_DEVICES; i++) {
150                 struct obd_device *obd = &obd_dev[i];
151                 if (obd->obd_name && strncmp(name, obd->obd_uuid, 37) == 0) {
152                         return obd;
153                 }
154         }
155
156         return NULL;
157 }
158
159 void obd_cleanup_caches(void)
160 {
161         int rc;
162         ENTRY;
163         if (obdo_cachep) { 
164                 rc = kmem_cache_destroy(obdo_cachep);
165                 if (rc)
166                         CERROR("Cannot destory obdo_cachep\n");
167                 obdo_cachep = NULL;
168         }
169         if (import_cachep) { 
170                 rc = kmem_cache_destroy(import_cachep);
171                 if (rc)
172                         CERROR("Cannot destory import_cachep\n");
173                 import_cachep = NULL;
174         }
175         if (export_cachep) { 
176                 rc = kmem_cache_destroy(export_cachep);
177                 if (rc)
178                         CERROR("Cannot destory import_cachep\n");
179                 export_cachep = NULL;
180         }
181         EXIT;
182 }
183
184 int obd_init_caches(void)
185 {
186         ENTRY;
187         if (obdo_cachep == NULL) {
188                 obdo_cachep = kmem_cache_create("obdo_cache",
189                                                 sizeof(struct obdo),
190                                                 0, SLAB_HWCACHE_ALIGN,
191                                                 NULL, NULL);
192                 if (obdo_cachep == NULL)
193                         GOTO(out, -ENOMEM);
194         }
195
196         if (export_cachep == NULL) {
197                 export_cachep = kmem_cache_create("export_cache",
198                                                 sizeof(struct obd_export),
199                                                 0, SLAB_HWCACHE_ALIGN,
200                                                 NULL, NULL);
201                 if (export_cachep == NULL)
202                         GOTO(out, -ENOMEM);
203         }
204
205         if (import_cachep == NULL) {
206                 import_cachep = kmem_cache_create("import_cache",
207                                                 sizeof(struct obd_import),
208                                                 0, SLAB_HWCACHE_ALIGN,
209                                                 NULL, NULL);
210                 if (import_cachep == NULL)
211                         GOTO(out, -ENOMEM);
212         }
213         RETURN(0);
214  out:
215         obd_cleanup_caches();
216         RETURN(-ENOMEM);
217
218 }
219
220 /* map connection to client */
221 struct obd_export *class_conn2export(struct lustre_handle *conn)
222 {
223         struct obd_export * export;
224
225         if (!conn)
226                 RETURN(NULL);
227
228         if (!conn->addr || conn->addr == -1 ) { 
229                 fixme();
230                 RETURN(NULL);
231         }
232               
233         export = (struct obd_export *) (unsigned long)conn->addr;
234         if (!kmem_cache_validate(export_cachep, (void *)export))
235                 RETURN(NULL);
236
237         if (export->export_cookie != conn->cookie)
238                 return NULL;
239         return export;
240 } /* class_conn2export */
241
242 struct obd_device *class_conn2obd(struct lustre_handle *conn)
243 {
244         struct obd_export *export;
245         export = class_conn2export(conn); 
246         if (export) 
247                 return export->export_obd;
248         fixme();
249         return NULL;
250 }
251
252 /* a connection defines an export context in which preallocation can
253    be managed. */
254 int class_connect (struct lustre_handle *conn, struct obd_device *obd)
255 {
256         struct obd_export * export;
257
258         export = kmem_cache_alloc(export_cachep, GFP_KERNEL); 
259         if ( !export ) {
260                 CERROR("no memory! (minor %d)\n", obd->obd_minor);
261                 return -ENOMEM;
262         }
263
264         memset(export, 0, sizeof(*export));
265         get_random_bytes(&export->export_cookie, sizeof(__u64));
266         export->export_obd = obd; 
267         export->export_import.addr = conn->addr;
268         export->export_import.cookie = conn->cookie;
269         
270         list_add(&(export->export_chain), export->export_obd->obd_exports.prev);
271         conn->addr = (__u64) (unsigned long)export;
272         conn->cookie = export->export_cookie;
273         return 0;
274
275
276 int class_disconnect(struct lustre_handle *conn)
277 {
278         struct obd_export * export;
279         ENTRY;
280
281         if (!(export = class_conn2export(conn))) {
282                 fixme();
283                 CDEBUG(D_IOCTL, "disconnect: attempting to free "
284                        "nonexistent client %Lx\n", conn->addr);
285                 RETURN(-EINVAL);
286         }
287         list_del(&export->export_chain);
288         kmem_cache_free(export_cachep, export);
289
290         RETURN(0);
291
292
293 #if 0
294
295 /* FIXME: Data is a space- or comma-separated list of device IDs.  This will
296  * have to change. */
297 int class_multi_setup(struct obd_device *obddev, uint32_t len, void *data)
298 {
299         int count, rc;
300         char *p;
301         ENTRY;
302
303         for (p = data, count = 0; p < (char *)data + len; count++) {
304                 char *end;
305                 int tmp = simple_strtoul(p, &end, 0);
306
307                 if (p == end) {
308                         CERROR("invalid device ID starting at: %s\n", p);
309                         GOTO(err_disconnect, rc = -EINVAL);
310                 }
311                 
312                 if (tmp < 0 || tmp >= MAX_OBD_DEVICES) { 
313                         CERROR("Trying to sub dev %d  - dev no too large\n", 
314                                tmp);
315                         GOTO(err_disconnect, rc  = -EINVAL); 
316                 }
317
318                 rc = obd_connect(&obddev->obd_multi_conn[count], &obd_dev[tmp]);
319                 if (rc) {
320                         CERROR("cannot connect to device %d: rc = %d\n", tmp,
321                                rc);
322                         GOTO(err_disconnect, rc);
323                 }
324
325                 CDEBUG(D_INFO, "target OBD %d is of type %s\n", count,
326                        obd_dev[tmp].obd_type->typ_name);
327
328                 p = end + 1;
329         }
330
331         obddev->obd_multi_count = count;
332
333         RETURN(0);
334
335  err_disconnect:
336         for (count--; count >= 0; count--)
337                 obd_disconnect(&obddev->obd_multi_conn[count]);
338         return rc;
339 }
340
341 /*
342  *    remove all connections to this device
343  *    close all connections to lower devices
344  *    needed for forced unloads of OBD client drivers
345  */
346 int class_multi_cleanup(struct obd_device *obddev)
347 {
348         int i;
349
350         for (i = 0; i < obddev->obd_multi_count; i++) {
351                 int rc;
352                 struct obd_device *obd = class_conn2obd(&obddev->obd_multi_conn[i]);
353
354                 if (!obd) { 
355                         CERROR("no such device [i %d]\n", i); 
356                         RETURN(-EINVAL);
357                 }
358
359                 rc = obd_disconnect(&obddev->obd_multi_conn[i]);
360                 if (rc)
361                         CERROR("disconnect failure %d\n", obd->obd_minor);
362         }
363         return 0;
364 }
365 #endif