Whamcloud - gitweb
LU-6401 uapi: migrate remaining uapi headers to uapi directory
[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 <uapi/linux/lnet/lnetctl.h>
45 #include <lustre_debug.h>
46 #include <lustre_kernelcomm.h>
47 #include <lprocfs_status.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 <uapi/linux/lustre/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 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
260         case OBD_GET_VERSION: {
261                 static bool warned;
262
263                 if (!data->ioc_inlbuf1) {
264                         CERROR("No buffer passed in ioctl\n");
265                         GOTO(out, err = -EINVAL);
266                 }
267
268                 if (strlen(LUSTRE_VERSION_STRING) + 1 > data->ioc_inllen1) {
269                         CERROR("ioctl buffer too small to hold version\n");
270                         GOTO(out, err = -EINVAL);
271                 }
272
273                 if (!warned) {
274                         warned = true;
275                         CWARN("%s: ioctl(OBD_GET_VERSION) is deprecated, "
276                               "use llapi_get_version_string() and/or relink\n",
277                               current->comm);
278                 }
279                 memcpy(data->ioc_bulk, LUSTRE_VERSION_STRING,
280                        strlen(LUSTRE_VERSION_STRING) + 1);
281
282                 if (copy_to_user((void __user *)arg, data, len))
283                         err = -EFAULT;
284                 GOTO(out, err);
285         }
286 #endif
287         case OBD_IOC_NAME2DEV: {
288                 /* Resolve a device name.  This does not change the
289                  * currently selected device.
290                  */
291                 int dev;
292
293                 dev = class_resolve_dev_name(data->ioc_inllen1,
294                                              data->ioc_inlbuf1);
295                 data->ioc_dev = dev;
296                 if (dev < 0)
297                         GOTO(out, err = -EINVAL);
298
299                 if (copy_to_user((void __user *)arg, data, sizeof(*data)))
300                         err = -EFAULT;
301                 GOTO(out, err);
302         }
303
304         case OBD_IOC_UUID2DEV: {
305                 /* Resolve a device uuid.  This does not change the
306                  * currently selected device.
307                  */
308                 int dev;
309                 struct obd_uuid uuid;
310
311                 if (!data->ioc_inllen1 || !data->ioc_inlbuf1) {
312                         CERROR("No UUID passed!\n");
313                         GOTO(out, err = -EINVAL);
314                 }
315                 if (data->ioc_inlbuf1[data->ioc_inllen1 - 1] != 0) {
316                         CERROR("UUID not NUL terminated!\n");
317                         GOTO(out, err = -EINVAL);
318                 }
319
320                 CDEBUG(D_IOCTL, "device name %s\n", data->ioc_inlbuf1);
321                 obd_str2uuid(&uuid, data->ioc_inlbuf1);
322                 dev = class_uuid2dev(&uuid);
323                 data->ioc_dev = dev;
324                 if (dev == -1) {
325                         CDEBUG(D_IOCTL, "No device for UUID %s!\n",
326                                data->ioc_inlbuf1);
327                         GOTO(out, err = -EINVAL);
328                 }
329
330                 CDEBUG(D_IOCTL, "device name %s, dev %d\n", data->ioc_inlbuf1,
331                        dev);
332                 if (copy_to_user((void __user *)arg, data, sizeof(*data)))
333                         err = -EFAULT;
334                 GOTO(out, err);
335         }
336
337         case OBD_IOC_GETDEVICE: {
338                 int     index = data->ioc_count;
339                 char    *status, *str;
340
341                 if (!data->ioc_inlbuf1) {
342                         CERROR("No buffer passed in ioctl\n");
343                         GOTO(out, err = -EINVAL);
344                 }
345                 if (data->ioc_inllen1 < 128) {
346                         CERROR("ioctl buffer too small to hold version\n");
347                         GOTO(out, err = -EINVAL);
348                 }
349
350                 obd = class_num2obd(index);
351                 if (!obd)
352                         GOTO(out, err = -ENOENT);
353
354                 if (obd->obd_stopping)
355                         status = "ST";
356                 else if (obd->obd_set_up)
357                         status = "UP";
358                 else if (obd->obd_attached)
359                         status = "AT";
360                 else
361                         status = "--";
362                 str = (char *)data->ioc_bulk;
363                 snprintf(str, len - sizeof(*data), "%3d %s %s %s %s %d",
364                          (int)index, status, obd->obd_type->typ_name,
365                          obd->obd_name, obd->obd_uuid.uuid,
366                          atomic_read(&obd->obd_refcount));
367
368                 if (copy_to_user((void __user *)arg, data, len))
369                         err = -EFAULT;
370
371                 GOTO(out, err);
372         }
373
374         }
375
376         if (data->ioc_dev == OBD_DEV_BY_DEVNAME) {
377                 if (data->ioc_inllen4 <= 0 || data->ioc_inlbuf4 == NULL)
378                         GOTO(out, err = -EINVAL);
379                 if (strnlen(data->ioc_inlbuf4, MAX_OBD_NAME) >= MAX_OBD_NAME)
380                         GOTO(out, err = -EINVAL);
381                 obd = class_name2obd(data->ioc_inlbuf4);
382         } else if (data->ioc_dev < class_devno_max()) {
383                 obd = class_num2obd(data->ioc_dev);
384         } else {
385                 CERROR("OBD ioctl: No device\n");
386                 GOTO(out, err = -EINVAL);
387         }
388
389         if (obd == NULL) {
390                 CERROR("OBD ioctl : No Device %d\n", data->ioc_dev);
391                 GOTO(out, err = -EINVAL);
392         }
393         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
394
395         if (!obd->obd_set_up || obd->obd_stopping) {
396                 CERROR("OBD ioctl: device not setup %d \n", data->ioc_dev);
397                 GOTO(out, err = -EINVAL);
398         }
399
400         switch(cmd) {
401         case OBD_IOC_NO_TRANSNO: {
402                 if (!obd->obd_attached) {
403                         CERROR("Device %d not attached\n", obd->obd_minor);
404                         GOTO(out, err = -ENODEV);
405                 }
406                 CDEBUG(D_HA, "%s: disabling committed-transno notification\n",
407                        obd->obd_name);
408                 obd->obd_no_transno = 1;
409                 GOTO(out, err = 0);
410         }
411
412         default: {
413                 err = obd_iocontrol(cmd, obd->obd_self_export, len, data, NULL);
414                 if (err)
415                         GOTO(out, err);
416
417                 if (copy_to_user((void __user *)arg, data, len))
418                         err = -EFAULT;
419                 GOTO(out, err);
420         }
421         }
422
423 out:
424         OBD_FREE_LARGE(buf, len);
425         RETURN(err);
426 } /* class_handle_ioctl */
427
428 #define OBD_INIT_CHECK
429 #ifdef OBD_INIT_CHECK
430 static int obd_init_checks(void)
431 {
432         __u64 u64val, div64val;
433         char buf[64];
434         int len, ret = 0;
435
436         CDEBUG(D_INFO, "OBD_OBJECT_EOF = %#llx\n", (__u64)OBD_OBJECT_EOF);
437
438         u64val = OBD_OBJECT_EOF;
439         CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = %#llx\n", u64val);
440         if (u64val != OBD_OBJECT_EOF) {
441                 CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n",
442                        u64val, (int)sizeof(u64val));
443                 ret = -EINVAL;
444         }
445         len = snprintf(buf, sizeof(buf), "%#llx", u64val);
446         if (len != 18) {
447                 CWARN("u64 hex wrong length! strlen(%s)=%d != 18\n", buf, len);
448                 ret = -EINVAL;
449         }
450
451         div64val = OBD_OBJECT_EOF;
452         CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = %#llx\n", u64val);
453         if (u64val != OBD_OBJECT_EOF) {
454                 CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n",
455                        u64val, (int)sizeof(u64val));
456                 ret = -EOVERFLOW;
457         }
458         if (u64val >> 8 != OBD_OBJECT_EOF >> 8) {
459                 CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n",
460                        u64val, (int)sizeof(u64val));
461                 return -EOVERFLOW;
462         }
463         if (do_div(div64val, 256) != (u64val & 255)) {
464                 CERROR("do_div(%#llx,256) != %llu\n", u64val, u64val & 255);
465                 return -EOVERFLOW;
466         }
467         if (u64val >> 8 != div64val) {
468                 CERROR("do_div(%#llx,256) %llu != %llu\n",
469                        u64val, div64val, u64val >> 8);
470                 return -EOVERFLOW;
471         }
472         len = snprintf(buf, sizeof(buf), "%#llx", u64val);
473         if (len != 18) {
474                 CWARN("u64 hex wrong length! strlen(%s)=%d != 18\n", buf, len);
475                 ret = -EINVAL;
476         }
477         len = snprintf(buf, sizeof(buf), "%llu", u64val);
478         if (len != 20) {
479                 CWARN("u64 wrong length! strlen(%s)=%d != 20\n", buf, len);
480                 ret = -EINVAL;
481         }
482         len = snprintf(buf, sizeof(buf), "%lld", u64val);
483         if (len != 2) {
484                 CWARN("s64 wrong length! strlen(%s)=%d != 2\n", buf, len);
485                 ret = -EINVAL;
486         }
487         if ((u64val & ~PAGE_MASK) >= PAGE_SIZE) {
488                 CWARN("mask failed: u64val %llu >= %llu\n", u64val,
489                       (__u64)PAGE_SIZE);
490                 ret = -EINVAL;
491         }
492
493         return ret;
494 }
495 #else
496 #define obd_init_checks() do {} while(0)
497 #endif
498
499 static int __init obdclass_init(void)
500 {
501         int err;
502
503         LCONSOLE_INFO("Lustre: Build Version: "LUSTRE_VERSION_STRING"\n");
504
505         libcfs_kkuc_init();
506
507         err = obd_init_checks();
508         if (err == -EOVERFLOW)
509                 return err;
510
511 #ifdef CONFIG_PROC_FS
512         obd_memory = lprocfs_alloc_stats(OBD_STATS_NUM,
513                                          LPROCFS_STATS_FLAG_NONE |
514                                          LPROCFS_STATS_FLAG_IRQ_SAFE);
515         if (obd_memory == NULL) {
516                 CERROR("kmalloc of 'obd_memory' failed\n");
517                 return -ENOMEM;
518         }
519
520         lprocfs_counter_init(obd_memory, OBD_MEMORY_STAT,
521                              LPROCFS_CNTR_AVGMINMAX,
522                              "memused", "bytes");
523 #endif
524         err = obd_zombie_impexp_init();
525         if (err)
526                 goto cleanup_obd_memory;
527
528         err = class_handle_init();
529         if (err)
530                 goto cleanup_zombie_impexp;
531
532         err = misc_register(&obd_psdev);
533         if (err) {
534                 CERROR("cannot register %d err %d\n", OBD_DEV_MINOR, err);
535                 goto cleanup_class_handle;
536         }
537
538         /* Default the dirty page cache cap to 1/2 of system memory.
539          * For clients with less memory, a larger fraction is needed
540          * for other purposes (mostly for BGL). */
541         if (totalram_pages <= 512 << (20 - PAGE_SHIFT))
542                 obd_max_dirty_pages = totalram_pages / 4;
543         else
544                 obd_max_dirty_pages = totalram_pages / 2;
545
546         err = obd_init_caches();
547         if (err)
548                 goto cleanup_deregister;
549
550         err = class_procfs_init();
551         if (err)
552                 goto cleanup_caches;
553
554         err = lu_global_init();
555         if (err)
556                 goto cleanup_class_procfs;
557
558         err = cl_global_init();
559         if (err != 0)
560                 goto cleanup_lu_global;
561
562 #ifdef HAVE_SERVER_SUPPORT
563         err = dt_global_init();
564         if (err != 0)
565                 goto cleanup_cl_global;
566
567         err = lu_ucred_global_init();
568         if (err != 0)
569                 goto cleanup_dt_global;
570 #endif /* HAVE_SERVER_SUPPORT */
571
572         err = llog_info_init();
573         if (err)
574 #ifdef HAVE_SERVER_SUPPORT
575                 goto cleanup_lu_ucred_global;
576 #else /* !HAVE_SERVER_SUPPORT */
577                 goto cleanup_cl_global;
578 #endif /* HAVE_SERVER_SUPPORT */
579
580         err = lustre_register_fs();
581
582         /* simulate a late OOM situation now to require all
583          * alloc'ed/initialized resources to be freed */
584         if (OBD_FAIL_CHECK(OBD_FAIL_OBDCLASS_MODULE_LOAD)) {
585                 /* fake error but filesystem has been registered */
586                 lustre_unregister_fs();
587                 /* force error to ensure module will be unloaded/cleaned */
588                 err = -ENOMEM;
589         }
590
591         if (err)
592                 goto cleanup_llog_info;
593
594         return 0;
595
596 cleanup_llog_info:
597         llog_info_fini();
598
599 #ifdef HAVE_SERVER_SUPPORT
600 cleanup_lu_ucred_global:
601         lu_ucred_global_fini();
602
603 cleanup_dt_global:
604         dt_global_fini();
605 #endif /* HAVE_SERVER_SUPPORT */
606
607 cleanup_cl_global:
608         cl_global_fini();
609
610 cleanup_lu_global:
611         lu_global_fini();
612
613 cleanup_class_procfs:
614         obd_sysctl_clean();
615         class_procfs_clean();
616
617 cleanup_caches:
618         obd_cleanup_caches();
619
620 cleanup_deregister:
621         misc_deregister(&obd_psdev);
622
623 cleanup_class_handle:
624         class_handle_cleanup();
625
626 cleanup_zombie_impexp:
627         obd_zombie_impexp_stop();
628
629 cleanup_obd_memory:
630 #ifdef CONFIG_PROC_FS
631         lprocfs_free_stats(&obd_memory);
632 #endif
633
634         return err;
635 }
636
637 void obd_update_maxusage(void)
638 {
639         __u64 max;
640
641         max = obd_memory_sum();
642
643         spin_lock(&obd_updatemax_lock);
644         if (max > obd_max_alloc)
645                 obd_max_alloc = max;
646         spin_unlock(&obd_updatemax_lock);
647 }
648 EXPORT_SYMBOL(obd_update_maxusage);
649
650 #ifdef CONFIG_PROC_FS
651 __u64 obd_memory_max(void)
652 {
653         __u64 ret;
654
655         obd_update_maxusage();
656         spin_lock(&obd_updatemax_lock);
657         ret = obd_max_alloc;
658         spin_unlock(&obd_updatemax_lock);
659
660         return ret;
661 }
662 #endif /* CONFIG_PROC_FS */
663
664 static void __exit obdclass_exit(void)
665 {
666 #ifdef CONFIG_PROC_FS
667         __u64 memory_leaked;
668         __u64 memory_max;
669 #endif /* CONFIG_PROC_FS */
670         ENTRY;
671
672         lustre_unregister_fs();
673
674         misc_deregister(&obd_psdev);
675         llog_info_fini();
676 #ifdef HAVE_SERVER_SUPPORT
677         lu_ucred_global_fini();
678         dt_global_fini();
679 #endif /* HAVE_SERVER_SUPPORT */
680         cl_global_fini();
681         lu_global_fini();
682
683         obd_cleanup_caches();
684         obd_sysctl_clean();
685
686         class_procfs_clean();
687
688         class_handle_cleanup();
689         class_del_uuid(NULL); /* Delete all UUIDs. */
690         obd_zombie_impexp_stop();
691
692 #ifdef CONFIG_PROC_FS
693         memory_leaked = obd_memory_sum();
694         memory_max = obd_memory_max();
695
696         lprocfs_free_stats(&obd_memory);
697         CDEBUG((memory_leaked) ? D_ERROR : D_INFO,
698                "obd_memory max: %llu, leaked: %llu\n",
699                memory_max, memory_leaked);
700 #endif /* CONFIG_PROC_FS */
701
702         EXIT;
703 }
704
705 MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
706 MODULE_DESCRIPTION("Lustre Class Driver");
707 MODULE_VERSION(LUSTRE_VERSION_STRING);
708 MODULE_LICENSE("GPL");
709
710 module_init(obdclass_init);
711 module_exit(obdclass_exit);