Whamcloud - gitweb
f644a3f1ef7f177ab66ec926694fcd0942307978
[fs/lustre-release.git] / lustre / obdclass / class_obd.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2015, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32
33 #define DEBUG_SUBSYSTEM S_CLASS
34
35 #include <linux/user_namespace.h>
36 #ifdef HAVE_UIDGID_HEADER
37 # include <linux/uidgid.h>
38 #endif
39 #include <linux/atomic.h>
40 #include <linux/list.h>
41
42 #include <obd_support.h>
43 #include <obd_class.h>
44 #include <lnet/lnetctl.h>
45 #include <lustre_debug.h>
46 #include <lprocfs_status.h>
47 #include <lustre_ver.h>
48 #include <cl_object.h>
49 #ifdef HAVE_SERVER_SUPPORT
50 # include <dt_object.h>
51 # include <md_object.h>
52 #endif /* HAVE_SERVER_SUPPORT */
53 #include <lustre_ioctl.h>
54 #include "llog_internal.h"
55
56 #ifdef CONFIG_PROC_FS
57 static __u64 obd_max_alloc;
58 #else
59 __u64 obd_max_alloc;
60 #endif
61
62 static DEFINE_SPINLOCK(obd_updatemax_lock);
63
64 /* The following are visible and mutable through /proc/sys/lustre/. */
65 unsigned int obd_debug_peer_on_timeout;
66 EXPORT_SYMBOL(obd_debug_peer_on_timeout);
67 unsigned int obd_dump_on_timeout;
68 EXPORT_SYMBOL(obd_dump_on_timeout);
69 unsigned int obd_dump_on_eviction;
70 EXPORT_SYMBOL(obd_dump_on_eviction);
71 unsigned long obd_max_dirty_pages;
72 EXPORT_SYMBOL(obd_max_dirty_pages);
73 atomic_long_t obd_dirty_pages;
74 EXPORT_SYMBOL(obd_dirty_pages);
75 unsigned int obd_timeout = OBD_TIMEOUT_DEFAULT;   /* seconds */
76 EXPORT_SYMBOL(obd_timeout);
77 unsigned int ldlm_timeout = LDLM_TIMEOUT_DEFAULT; /* seconds */
78 EXPORT_SYMBOL(ldlm_timeout);
79 unsigned int obd_timeout_set;
80 EXPORT_SYMBOL(obd_timeout_set);
81 unsigned int ldlm_timeout_set;
82 EXPORT_SYMBOL(ldlm_timeout_set);
83 /* bulk transfer timeout, give up after 100s by default */
84 unsigned int bulk_timeout = 100; /* seconds */
85 EXPORT_SYMBOL(bulk_timeout);
86 /* Adaptive timeout defs here instead of ptlrpc module for /proc/sys/ access */
87 unsigned int at_min = 0;
88 EXPORT_SYMBOL(at_min);
89 unsigned int at_max = 600;
90 EXPORT_SYMBOL(at_max);
91 unsigned int at_history = 600;
92 EXPORT_SYMBOL(at_history);
93 int at_early_margin = 5;
94 EXPORT_SYMBOL(at_early_margin);
95 int at_extra = 30;
96 EXPORT_SYMBOL(at_extra);
97
98 atomic_long_t obd_dirty_transit_pages;
99 EXPORT_SYMBOL(obd_dirty_transit_pages);
100
101 char obd_jobid_var[JOBSTATS_JOBID_VAR_MAX_LEN + 1] = JOBSTATS_DISABLE;
102
103 #ifdef CONFIG_PROC_FS
104 struct lprocfs_stats *obd_memory = NULL;
105 EXPORT_SYMBOL(obd_memory);
106 #endif
107
108 char obd_jobid_node[LUSTRE_JOBID_SIZE + 1];
109
110 /* Get jobid of current process by reading the environment variable
111  * stored in between the "env_start" & "env_end" of task struct.
112  *
113  * TODO:
114  * It's better to cache the jobid for later use if there is any
115  * efficient way, the cl_env code probably could be reused for this
116  * purpose.
117  *
118  * If some job scheduler doesn't store jobid in the "env_start/end",
119  * then an upcall could be issued here to get the jobid by utilizing
120  * the userspace tools/api. Then, the jobid must be cached.
121  */
122 int lustre_get_jobid(char *jobid)
123 {
124         int jobid_len = LUSTRE_JOBID_SIZE;
125         char tmp_jobid[LUSTRE_JOBID_SIZE] = { 0 };
126         int rc = 0;
127         ENTRY;
128
129         /* Jobstats isn't enabled */
130         if (strcmp(obd_jobid_var, JOBSTATS_DISABLE) == 0)
131                 GOTO(out, rc = 0);
132
133         /* Whole node dedicated to single job */
134         if (strcmp(obd_jobid_var, JOBSTATS_NODELOCAL) == 0) {
135                 memcpy(tmp_jobid, obd_jobid_node, LUSTRE_JOBID_SIZE);
136                 GOTO(out, rc = 0);
137         }
138
139         /* Use process name + fsuid as jobid */
140         if (strcmp(obd_jobid_var, JOBSTATS_PROCNAME_UID) == 0) {
141                 snprintf(tmp_jobid, LUSTRE_JOBID_SIZE, "%s.%u",
142                          current_comm(),
143                          from_kuid(&init_user_ns, current_fsuid()));
144                 GOTO(out, rc = 0);
145         }
146
147         rc = cfs_get_environ(obd_jobid_var, tmp_jobid, &jobid_len);
148         if (rc) {
149                 if (rc == -EOVERFLOW) {
150                         /* For the PBS_JOBID and LOADL_STEP_ID keys (which are
151                          * variable length strings instead of just numbers), it
152                          * might make sense to keep the unique parts for JobID,
153                          * instead of just returning an error.  That means a
154                          * larger temp buffer for cfs_get_environ(), then
155                          * truncating the string at some separator to fit into
156                          * the specified jobid_len.  Fix later if needed. */
157                         static bool printed;
158                         if (unlikely(!printed)) {
159                                 LCONSOLE_ERROR_MSG(0x16b, "%s value too large "
160                                                    "for JobID buffer (%d)\n",
161                                                    obd_jobid_var, jobid_len);
162                                 printed = true;
163                         }
164                 } else {
165                         CDEBUG((rc == -ENOENT || rc == -EINVAL ||
166                                 rc == -EDEADLK) ? D_INFO : D_ERROR,
167                                "Get jobid for (%s) failed: rc = %d\n",
168                                obd_jobid_var, rc);
169                 }
170         }
171
172 out:
173         if (rc != 0)
174                 RETURN(rc);
175
176         /* Only replace the job ID if it changed. */
177         if (strcmp(jobid, tmp_jobid) != 0)
178                 memcpy(jobid, tmp_jobid, jobid_len);
179
180         RETURN(0);
181 }
182 EXPORT_SYMBOL(lustre_get_jobid);
183
184 static int class_resolve_dev_name(__u32 len, const char *name)
185 {
186         int rc;
187         int dev;
188
189         ENTRY;
190         if (!len || !name) {
191                 CERROR("No name passed,!\n");
192                 GOTO(out, rc = -EINVAL);
193         }
194         if (name[len - 1] != 0) {
195                 CERROR("Name not nul terminated!\n");
196                 GOTO(out, rc = -EINVAL);
197         }
198
199         CDEBUG(D_IOCTL, "device name %s\n", name);
200         dev = class_name2dev(name);
201         if (dev == -1) {
202                 CDEBUG(D_IOCTL, "No device for name %s!\n", name);
203                 GOTO(out, rc = -EINVAL);
204         }
205
206         CDEBUG(D_IOCTL, "device name %s, dev %d\n", name, dev);
207         rc = dev;
208
209 out:
210         RETURN(rc);
211 }
212
213 int class_handle_ioctl(unsigned int cmd, unsigned long arg)
214 {
215         char *buf = NULL;
216         struct obd_ioctl_data *data;
217         struct libcfs_debug_ioctl_data *debug_data;
218         struct obd_device *obd = NULL;
219         int err = 0, len = 0;
220         ENTRY;
221
222         /* only for debugging */
223         if (cmd == LIBCFS_IOC_DEBUG_MASK) {
224                 debug_data = (struct libcfs_debug_ioctl_data*)arg;
225                 libcfs_subsystem_debug = debug_data->subs;
226                 libcfs_debug = debug_data->debug;
227                 return 0;
228         }
229
230         CDEBUG(D_IOCTL, "cmd = %x\n", cmd);
231         if (obd_ioctl_getdata(&buf, &len, (void __user *)arg)) {
232                 CERROR("OBD ioctl: data error\n");
233                 RETURN(-EINVAL);
234         }
235         data = (struct obd_ioctl_data *)buf;
236
237         switch (cmd) {
238         case OBD_IOC_PROCESS_CFG: {
239                 struct lustre_cfg *lcfg;
240
241                 if (!data->ioc_plen1 || !data->ioc_pbuf1) {
242                         CERROR("No config buffer passed!\n");
243                         GOTO(out, err = -EINVAL);
244                 }
245                 OBD_ALLOC(lcfg, data->ioc_plen1);
246                 if (lcfg == NULL)
247                         GOTO(out, err = -ENOMEM);
248                 err = copy_from_user(lcfg, data->ioc_pbuf1,
249                                          data->ioc_plen1);
250                 if (!err)
251                         err = lustre_cfg_sanity_check(lcfg, data->ioc_plen1);
252                 if (!err)
253                         err = class_process_config(lcfg);
254
255                 OBD_FREE(lcfg, data->ioc_plen1);
256                 GOTO(out, err);
257         }
258
259         case OBD_GET_VERSION:
260                 if (!data->ioc_inlbuf1) {
261                         CERROR("No buffer passed in ioctl\n");
262                         GOTO(out, err = -EINVAL);
263                 }
264
265                 if (strlen(LUSTRE_VERSION_STRING) + 1 > data->ioc_inllen1) {
266                         CERROR("ioctl buffer too small to hold version\n");
267                         GOTO(out, err = -EINVAL);
268                 }
269
270                 memcpy(data->ioc_bulk, LUSTRE_VERSION_STRING,
271                        strlen(LUSTRE_VERSION_STRING) + 1);
272
273                 err = obd_ioctl_popdata((void __user *)arg, data, len);
274                 if (err)
275                         err = -EFAULT;
276                 GOTO(out, err);
277
278         case OBD_IOC_NAME2DEV: {
279                 /* Resolve a device name.  This does not change the
280                  * currently selected device.
281                  */
282                 int dev;
283
284                 dev = class_resolve_dev_name(data->ioc_inllen1,
285                                              data->ioc_inlbuf1);
286                 data->ioc_dev = dev;
287                 if (dev < 0)
288                         GOTO(out, err = -EINVAL);
289
290                 err = obd_ioctl_popdata((void __user *)arg, data,
291                                         sizeof(*data));
292                 if (err)
293                         err = -EFAULT;
294                 GOTO(out, err);
295         }
296
297         case OBD_IOC_UUID2DEV: {
298                 /* Resolve a device uuid.  This does not change the
299                  * currently selected device.
300                  */
301                 int dev;
302                 struct obd_uuid uuid;
303
304                 if (!data->ioc_inllen1 || !data->ioc_inlbuf1) {
305                         CERROR("No UUID passed!\n");
306                         GOTO(out, err = -EINVAL);
307                 }
308                 if (data->ioc_inlbuf1[data->ioc_inllen1 - 1] != 0) {
309                         CERROR("UUID not NUL terminated!\n");
310                         GOTO(out, err = -EINVAL);
311                 }
312
313                 CDEBUG(D_IOCTL, "device name %s\n", data->ioc_inlbuf1);
314                 obd_str2uuid(&uuid, data->ioc_inlbuf1);
315                 dev = class_uuid2dev(&uuid);
316                 data->ioc_dev = dev;
317                 if (dev == -1) {
318                         CDEBUG(D_IOCTL, "No device for UUID %s!\n",
319                                data->ioc_inlbuf1);
320                         GOTO(out, err = -EINVAL);
321                 }
322
323                 CDEBUG(D_IOCTL, "device name %s, dev %d\n", data->ioc_inlbuf1,
324                        dev);
325                 err = obd_ioctl_popdata((void __user *)arg, data,
326                                         sizeof(*data));
327                 if (err)
328                         err = -EFAULT;
329                 GOTO(out, err);
330         }
331
332         case OBD_IOC_GETDEVICE: {
333                 int     index = data->ioc_count;
334                 char    *status, *str;
335
336                 if (!data->ioc_inlbuf1) {
337                         CERROR("No buffer passed in ioctl\n");
338                         GOTO(out, err = -EINVAL);
339                 }
340                 if (data->ioc_inllen1 < 128) {
341                         CERROR("ioctl buffer too small to hold version\n");
342                         GOTO(out, err = -EINVAL);
343                 }
344
345                 obd = class_num2obd(index);
346                 if (!obd)
347                         GOTO(out, err = -ENOENT);
348
349                 if (obd->obd_stopping)
350                         status = "ST";
351                 else if (obd->obd_set_up)
352                         status = "UP";
353                 else if (obd->obd_attached)
354                         status = "AT";
355                 else
356                         status = "--";
357                 str = (char *)data->ioc_bulk;
358                 snprintf(str, len - sizeof(*data), "%3d %s %s %s %s %d",
359                          (int)index, status, obd->obd_type->typ_name,
360                          obd->obd_name, obd->obd_uuid.uuid,
361                          atomic_read(&obd->obd_refcount));
362                 err = obd_ioctl_popdata((void __user *)arg, data, len);
363
364                 GOTO(out, err = 0);
365         }
366
367         }
368
369         if (data->ioc_dev == OBD_DEV_BY_DEVNAME) {
370                 if (data->ioc_inllen4 <= 0 || data->ioc_inlbuf4 == NULL)
371                         GOTO(out, err = -EINVAL);
372                 if (strnlen(data->ioc_inlbuf4, MAX_OBD_NAME) >= MAX_OBD_NAME)
373                         GOTO(out, err = -EINVAL);
374                 obd = class_name2obd(data->ioc_inlbuf4);
375         } else if (data->ioc_dev < class_devno_max()) {
376                 obd = class_num2obd(data->ioc_dev);
377         } else {
378                 CERROR("OBD ioctl: No device\n");
379                 GOTO(out, err = -EINVAL);
380         }
381
382         if (obd == NULL) {
383                 CERROR("OBD ioctl : No Device %d\n", data->ioc_dev);
384                 GOTO(out, err = -EINVAL);
385         }
386         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
387
388         if (!obd->obd_set_up || obd->obd_stopping) {
389                 CERROR("OBD ioctl: device not setup %d \n", data->ioc_dev);
390                 GOTO(out, err = -EINVAL);
391         }
392
393         switch(cmd) {
394         case OBD_IOC_NO_TRANSNO: {
395                 if (!obd->obd_attached) {
396                         CERROR("Device %d not attached\n", obd->obd_minor);
397                         GOTO(out, err = -ENODEV);
398                 }
399                 CDEBUG(D_HA, "%s: disabling committed-transno notification\n",
400                        obd->obd_name);
401                 obd->obd_no_transno = 1;
402                 GOTO(out, err = 0);
403         }
404
405         default: {
406                 err = obd_iocontrol(cmd, obd->obd_self_export, len, data, NULL);
407                 if (err)
408                         GOTO(out, err);
409
410                 err = obd_ioctl_popdata((void __user *)arg, data, len);
411                 if (err)
412                         err = -EFAULT;
413                 GOTO(out, err);
414         }
415         }
416
417  out:
418         if (buf)
419                 obd_ioctl_freedata(buf, len);
420         RETURN(err);
421 } /* class_handle_ioctl */
422
423 #define OBD_INIT_CHECK
424 #ifdef OBD_INIT_CHECK
425 static int obd_init_checks(void)
426 {
427         __u64 u64val, div64val;
428         char buf[64];
429         int len, ret = 0;
430
431         CDEBUG(D_INFO, "OBD_OBJECT_EOF = %#llx\n", (__u64)OBD_OBJECT_EOF);
432
433         u64val = OBD_OBJECT_EOF;
434         CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = %#llx\n", u64val);
435         if (u64val != OBD_OBJECT_EOF) {
436                 CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n",
437                        u64val, (int)sizeof(u64val));
438                 ret = -EINVAL;
439         }
440         len = snprintf(buf, sizeof(buf), "%#llx", u64val);
441         if (len != 18) {
442                 CWARN("u64 hex wrong length! strlen(%s)=%d != 18\n", buf, len);
443                 ret = -EINVAL;
444         }
445
446         div64val = OBD_OBJECT_EOF;
447         CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = %#llx\n", u64val);
448         if (u64val != OBD_OBJECT_EOF) {
449                 CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n",
450                        u64val, (int)sizeof(u64val));
451                 ret = -EOVERFLOW;
452         }
453         if (u64val >> 8 != OBD_OBJECT_EOF >> 8) {
454                 CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n",
455                        u64val, (int)sizeof(u64val));
456                 return -EOVERFLOW;
457         }
458         if (do_div(div64val, 256) != (u64val & 255)) {
459                 CERROR("do_div(%#llx,256) != %llu\n", u64val, u64val & 255);
460                 return -EOVERFLOW;
461         }
462         if (u64val >> 8 != div64val) {
463                 CERROR("do_div(%#llx,256) %llu != %llu\n",
464                        u64val, div64val, u64val >> 8);
465                 return -EOVERFLOW;
466         }
467         len = snprintf(buf, sizeof(buf), "%#llx", u64val);
468         if (len != 18) {
469                 CWARN("u64 hex wrong length! strlen(%s)=%d != 18\n", buf, len);
470                 ret = -EINVAL;
471         }
472         len = snprintf(buf, sizeof(buf), "%llu", u64val);
473         if (len != 20) {
474                 CWARN("u64 wrong length! strlen(%s)=%d != 20\n", buf, len);
475                 ret = -EINVAL;
476         }
477         len = snprintf(buf, sizeof(buf), "%lld", u64val);
478         if (len != 2) {
479                 CWARN("s64 wrong length! strlen(%s)=%d != 2\n", buf, len);
480                 ret = -EINVAL;
481         }
482         if ((u64val & ~PAGE_MASK) >= PAGE_SIZE) {
483                 CWARN("mask failed: u64val %llu >= %llu\n", u64val,
484                       (__u64)PAGE_SIZE);
485                 ret = -EINVAL;
486         }
487
488         return ret;
489 }
490 #else
491 #define obd_init_checks() do {} while(0)
492 #endif
493
494 static int __init obdclass_init(void)
495 {
496         int err;
497
498         LCONSOLE_INFO("Lustre: Build Version: "LUSTRE_VERSION_STRING"\n");
499
500         err = obd_init_checks();
501         if (err == -EOVERFLOW)
502                 return err;
503
504 #ifdef CONFIG_PROC_FS
505         obd_memory = lprocfs_alloc_stats(OBD_STATS_NUM,
506                                          LPROCFS_STATS_FLAG_NONE |
507                                          LPROCFS_STATS_FLAG_IRQ_SAFE);
508         if (obd_memory == NULL) {
509                 CERROR("kmalloc of 'obd_memory' failed\n");
510                 return -ENOMEM;
511         }
512
513         lprocfs_counter_init(obd_memory, OBD_MEMORY_STAT,
514                              LPROCFS_CNTR_AVGMINMAX,
515                              "memused", "bytes");
516 #endif
517         err = obd_zombie_impexp_init();
518         if (err)
519                 goto cleanup_obd_memory;
520
521         err = class_handle_init();
522         if (err)
523                 goto cleanup_zombie_impexp;
524
525         err = misc_register(&obd_psdev);
526         if (err) {
527                 CERROR("cannot register %d err %d\n", OBD_DEV_MINOR, err);
528                 goto cleanup_class_handle;
529         }
530
531         /* Default the dirty page cache cap to 1/2 of system memory.
532          * For clients with less memory, a larger fraction is needed
533          * for other purposes (mostly for BGL). */
534         if (totalram_pages <= 512 << (20 - PAGE_SHIFT))
535                 obd_max_dirty_pages = totalram_pages / 4;
536         else
537                 obd_max_dirty_pages = totalram_pages / 2;
538
539         err = obd_init_caches();
540         if (err)
541                 goto cleanup_deregister;
542
543         err = class_procfs_init();
544         if (err)
545                 goto cleanup_caches;
546
547         err = lu_global_init();
548         if (err)
549                 goto cleanup_class_procfs;
550
551         err = cl_global_init();
552         if (err != 0)
553                 goto cleanup_lu_global;
554
555 #ifdef HAVE_SERVER_SUPPORT
556         err = dt_global_init();
557         if (err != 0)
558                 goto cleanup_cl_global;
559
560         err = lu_ucred_global_init();
561         if (err != 0)
562                 goto cleanup_dt_global;
563 #endif /* HAVE_SERVER_SUPPORT */
564
565         err = llog_info_init();
566         if (err)
567 #ifdef HAVE_SERVER_SUPPORT
568                 goto cleanup_lu_ucred_global;
569 #else /* !HAVE_SERVER_SUPPORT */
570                 goto cleanup_cl_global;
571 #endif /* HAVE_SERVER_SUPPORT */
572
573         err = lustre_register_fs();
574
575         /* simulate a late OOM situation now to require all
576          * alloc'ed/initialized resources to be freed */
577         if (OBD_FAIL_CHECK(OBD_FAIL_OBDCLASS_MODULE_LOAD)) {
578                 /* fake error but filesystem has been registered */
579                 lustre_unregister_fs();
580                 /* force error to ensure module will be unloaded/cleaned */
581                 err = -ENOMEM;
582         }
583
584         if (err)
585                 goto cleanup_llog_info;
586
587         return 0;
588
589 cleanup_llog_info:
590         llog_info_fini();
591
592 #ifdef HAVE_SERVER_SUPPORT
593 cleanup_lu_ucred_global:
594         lu_ucred_global_fini();
595
596 cleanup_dt_global:
597         dt_global_fini();
598 #endif /* HAVE_SERVER_SUPPORT */
599
600 cleanup_cl_global:
601         cl_global_fini();
602
603 cleanup_lu_global:
604         lu_global_fini();
605
606 cleanup_class_procfs:
607         obd_sysctl_clean();
608         class_procfs_clean();
609
610 cleanup_caches:
611         obd_cleanup_caches();
612
613 cleanup_deregister:
614         misc_deregister(&obd_psdev);
615
616 cleanup_class_handle:
617         class_handle_cleanup();
618
619 cleanup_zombie_impexp:
620         obd_zombie_impexp_stop();
621
622 cleanup_obd_memory:
623 #ifdef CONFIG_PROC_FS
624         lprocfs_free_stats(&obd_memory);
625 #endif
626
627         return err;
628 }
629
630 void obd_update_maxusage(void)
631 {
632         __u64 max;
633
634         max = obd_memory_sum();
635
636         spin_lock(&obd_updatemax_lock);
637         if (max > obd_max_alloc)
638                 obd_max_alloc = max;
639         spin_unlock(&obd_updatemax_lock);
640 }
641 EXPORT_SYMBOL(obd_update_maxusage);
642
643 #ifdef CONFIG_PROC_FS
644 __u64 obd_memory_max(void)
645 {
646         __u64 ret;
647
648         obd_update_maxusage();
649         spin_lock(&obd_updatemax_lock);
650         ret = obd_max_alloc;
651         spin_unlock(&obd_updatemax_lock);
652
653         return ret;
654 }
655 #endif /* CONFIG_PROC_FS */
656
657 static void __exit obdclass_exit(void)
658 {
659 #ifdef CONFIG_PROC_FS
660         __u64 memory_leaked;
661         __u64 memory_max;
662 #endif /* CONFIG_PROC_FS */
663         ENTRY;
664
665         lustre_unregister_fs();
666
667         misc_deregister(&obd_psdev);
668         llog_info_fini();
669 #ifdef HAVE_SERVER_SUPPORT
670         lu_ucred_global_fini();
671         dt_global_fini();
672 #endif /* HAVE_SERVER_SUPPORT */
673         cl_global_fini();
674         lu_global_fini();
675
676         obd_cleanup_caches();
677         obd_sysctl_clean();
678
679         class_procfs_clean();
680
681         class_handle_cleanup();
682         class_del_uuid(NULL); /* Delete all UUIDs. */
683         obd_zombie_impexp_stop();
684
685 #ifdef CONFIG_PROC_FS
686         memory_leaked = obd_memory_sum();
687         memory_max = obd_memory_max();
688
689         lprocfs_free_stats(&obd_memory);
690         CDEBUG((memory_leaked) ? D_ERROR : D_INFO,
691                "obd_memory max: %llu, leaked: %llu\n",
692                memory_max, memory_leaked);
693 #endif /* CONFIG_PROC_FS */
694
695         EXIT;
696 }
697
698 MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
699 MODULE_DESCRIPTION("Lustre Class Driver");
700 MODULE_VERSION(LUSTRE_VERSION_STRING);
701 MODULE_LICENSE("GPL");
702
703 module_init(obdclass_init);
704 module_exit(obdclass_exit);